[CF915E] Physical Education Lessons - 动态开点线段树
Description
有 n 天(一开始都是工作日),之后会发布 q 个通知,通知的格式为:l r k。如果 k=1,就说明从第 l 天到第 r 天都变成非工作日;如果 k=2,就说明从第 l 天到第 r 天都变成工作日,每次操作后问有多少个工作日。
Solution
复习一下动态开点线段树,常数有点紧,空间大概要到 \(1.5\times 10^7\),需要 FASTIO
#include <bits/stdc++.h>
using namespace std;
const int N = 1.5e7;
int sum[N], tag[N], ch[N][2], ind, n, q, root;
#define LEFT ch[p][0], l, mid
#define RIGHT ch[p][1], mid + 1, r
#define MID ((l + r) >> 1)
inline int read()
{
int x(0);
char c = getchar();
while (!isdigit(c))
c = getchar();
while (isdigit(c))
x = (x * 10) + (c ^ 48), c = getchar();
return x;
}
void pushup(int p)
{
sum[p] = sum[ch[p][0]] + sum[ch[p][1]];
}
void pushdown(int p, int l, int r)
{
if (tag[p])
{
int mid = MID;
if (ch[p][0] == 0)
ch[p][0] = ++ind;
if (ch[p][1] == 0)
ch[p][1] = ++ind;
sum[ch[p][0]] = (mid - l + 1) * (2 - tag[p]);
sum[ch[p][1]] = (r - mid) * (2 - tag[p]);
tag[ch[p][0]] = tag[ch[p][1]] = tag[p];
tag[p] = 0;
}
}
void modify(int &p, int l, int r, int ql, int qr, int v)
{
int mid = MID;
if (l > qr || r < ql)
return;
if (!p)
p = ++ind;
if (l >= ql && r <= qr)
{
tag[p] = v;
sum[p] = (r - l + 1) * (2 - tag[p]);
}
else
{
pushdown(p, l, r);
if (ql <= mid)
modify(LEFT, ql, qr, v);
if (qr > mid)
modify(RIGHT, ql, qr, v);
pushup(p);
}
}
signed main()
{
ios::sync_with_stdio(false);
n = read();
q = read();
root = ++ind;
while (q--)
{
int l, r, k;
l = read();
r = read();
k = read();
modify(root, 1, n, l, r, k);
printf("%d\n", n - sum[1]);
}
}