[Luogu] P2572 [SCOI2010]序列操作
Description
lxhgww最近收到了一个\(01\)序列,序列里面包含了\(n\)个数,下标从\(0\)开始。这些数要么是\(0\),要么是\(1\),现在对于这个序列有五种变换操作和询问操作:
0 l r
把\([l,r]\)区间内的所有数全变成\(0\)1 l r
把\([l,r]\)区间内的所有数全变成\(1\)2 l r
把\([l,r]\)区间内的所有数全部取反,也就是说把所有的\(0\)变成\(1\),把所有的\(1\)变成\(0\)3 l r
询问\([l,r]\)区间内总共有多少个\(1\)4 l r
询问\([l,r]\)区间内最多有多少个连续的\(1\)
对于每一种询问操作,lxhgww 都需要给出回答,聪明的程序员们,你们能帮助他吗?
Solution
复杂的线段树。
考虑分别维护\(1\)的个数和,赋值标记,翻转标记,\(1\)和\(0\)的最长连续、最长前缀和后缀。注意顺序,分别维护即可。
这些其实开始都考虑到了,但就是翻转标记出了问题,调了我好久。之前我是写的如果有\(2\)操作,就标记翻转为\(1\),然后\(pushdown\)到子区间翻转标记都为\(1\),但这样是错的。因为某个标记放在那里,可能还没有下传。这时再来\(pushdown\)一个翻转标记,不就等于没有翻转吗?而对于我之前的想法,一个区间无论被不断翻转了多少次,都会被打上标记,就错了。所以标记应该是\(0\sim{1},1\sim{0}\)。
Code
#include <bits/stdc++.h>
using namespace std;
#define ls(x) (x << 1)
#define rs(x) (x << 1 | 1)
int n, m, a[100005];
struct node
{
int l, r, sum, tag, rev, mx1, suf1, pre1, mx2, suf2, pre2;
}t[400005];
int read()
{
int x = 0, fl = 1; char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') fl = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + ch - '0'; ch = getchar();}
return x * fl;
}
void push_up(int p)
{
t[p].sum = t[ls(p)].sum + t[rs(p)].sum;
t[p].mx1 = max(max(t[ls(p)].mx1, t[rs(p)].mx1), t[ls(p)].suf1 + t[rs(p)].pre1);
t[p].pre1 = t[ls(p)].pre1 + (t[ls(p)].pre1 == t[ls(p)].r - t[ls(p)].l + 1) * t[rs(p)].pre1;
t[p].suf1 = t[rs(p)].suf1 + (t[rs(p)].suf1 == t[rs(p)].r - t[rs(p)].l + 1) * t[ls(p)].suf1;
t[p].mx2 = max(max(t[ls(p)].mx2, t[rs(p)].mx2), t[ls(p)].suf2 + t[rs(p)].pre2);
t[p].pre2 = t[ls(p)].pre2 + (t[ls(p)].pre2 == t[ls(p)].r - t[ls(p)].l + 1) * t[rs(p)].pre2;
t[p].suf2 = t[rs(p)].suf2 + (t[rs(p)].suf2 == t[rs(p)].r - t[rs(p)].l + 1) * t[ls(p)].suf2;
return;
}
void push_down(int p)
{
if (t[p].tag != -1)
{
t[ls(p)].tag = t[rs(p)].tag = t[p].tag;
t[ls(p)].rev = t[rs(p)].rev = 0;
t[ls(p)].sum = (t[ls(p)].r - t[ls(p)].l + 1) * t[p].tag;
t[rs(p)].sum = (t[rs(p)].r - t[rs(p)].l + 1) * t[p].tag;
t[ls(p)].mx1 = (t[ls(p)].r - t[ls(p)].l + 1) * t[p].tag;
t[rs(p)].mx1 = (t[rs(p)].r - t[rs(p)].l + 1) * t[p].tag;
t[ls(p)].pre1 = (t[ls(p)].r - t[ls(p)].l + 1) * t[p].tag;
t[rs(p)].pre1 = (t[rs(p)].r - t[rs(p)].l + 1) * t[p].tag;
t[ls(p)].suf1 = (t[ls(p)].r - t[ls(p)].l + 1) * t[p].tag;
t[rs(p)].suf1 = (t[rs(p)].r - t[rs(p)].l + 1) * t[p].tag;
t[ls(p)].mx2 = (t[ls(p)].r - t[ls(p)].l + 1) * (!t[p].tag);
t[rs(p)].mx2 = (t[rs(p)].r - t[rs(p)].l + 1) * (!t[p].tag);
t[ls(p)].pre2 = (t[ls(p)].r - t[ls(p)].l + 1) * (!t[p].tag);
t[rs(p)].pre2 = (t[rs(p)].r - t[rs(p)].l + 1) * (!t[p].tag);
t[ls(p)].suf2 = (t[ls(p)].r - t[ls(p)].l + 1) * (!t[p].tag);
t[rs(p)].suf2 = (t[rs(p)].r - t[rs(p)].l + 1) * (!t[p].tag);
t[p].tag = -1;
}
if (t[p].rev)
{
t[ls(p)].rev = 1 - t[ls(p)].rev;
t[rs(p)].rev = 1 - t[rs(p)].rev;
t[ls(p)].sum = t[ls(p)].r - t[ls(p)].l + 1 - t[ls(p)].sum;
t[rs(p)].sum = t[rs(p)].r - t[rs(p)].l + 1 - t[rs(p)].sum;
swap(t[ls(p)].mx1, t[ls(p)].mx2); swap(t[ls(p)].pre1, t[ls(p)].pre2); swap(t[ls(p)].suf1, t[ls(p)].suf2);
swap(t[rs(p)].mx1, t[rs(p)].mx2); swap(t[rs(p)].pre1, t[rs(p)].pre2); swap(t[rs(p)].suf1, t[rs(p)].suf2);
t[p].rev = 0;
}
return;
}
void build(int p, int l0, int r0)
{
t[p].l = l0; t[p].r = r0; t[p].tag = -1;
if (l0 == r0)
{
t[p].sum = a[l0];
t[p].pre1 = t[p].suf1 = t[p].mx1 = a[l0];
t[p].pre2 = t[p].suf2 = t[p].mx2 = (!a[l0]);
return;
}
int mid = (t[p].l + t[p].r) >> 1;
build(ls(p), l0, mid);
build(rs(p), mid + 1, r0);
push_up(p);
return;
}
void update(int p, int l0, int r0, int tp)
{
if (l0 <= t[p].l && t[p].r <= r0)
{
if (tp == 1)
{
t[p].sum = 0; t[p].tag = 0; t[p].rev = 0;
t[p].mx1 = t[p].suf1 = t[p].pre1 = 0;
t[p].mx2 = t[p].suf2 = t[p].pre2 = t[p].r - t[p].l + 1;
}
else if (tp == 2)
{
t[p].sum = t[p].r - t[p].l + 1; t[p].tag = 1; t[p].rev = 0;
t[p].mx1 = t[p].suf1 = t[p].pre1 = t[p].r - t[p].l + 1;
t[p].mx2 = t[p].suf2 = t[p].pre2 = 0;
}
else
{
t[p].sum = (t[p].r - t[p].l + 1) - t[p].sum; t[p].rev = 1 - t[p].rev;
swap(t[p].mx1, t[p].mx2); swap(t[p].pre1, t[p].pre2); swap(t[p].suf1, t[p].suf2);
}
return;
}
push_down(p);
int mid = (t[p].l + t[p].r) >> 1;
if (l0 <= mid) update(ls(p), l0, r0, tp);
if (r0 > mid) update(rs(p), l0, r0, tp);
push_up(p);
return;
}
int query1(int p, int l0, int r0)
{
if (l0 <= t[p].l && t[p].r <= r0) return t[p].mx1;
push_down(p);
int mid = (t[p].l + t[p].r) >> 1, now = 0, tt = 0;
if (l0 <= mid) tt ++ , now = max(now, query1(ls(p), l0, r0));
if (r0 > mid) tt ++ , now = max(now, query1(rs(p), l0, r0));
if (tt == 2) now = max(now, min(t[ls(p)].suf1, t[ls(p)].r - l0 + 1) + min(t[rs(p)].pre1, r0 - t[rs(p)].l + 1));
return now;
}
int query2(int p, int l0, int r0)
{
if (l0 <= t[p].l && t[p].r <= r0) return t[p].sum;
push_down(p);
int mid = (t[p].l + t[p].r) >> 1, s = 0;
if (l0 <= mid) s = s + query2(ls(p), l0, r0);
if (r0 > mid) s = s + query2(rs(p), l0, r0);
return s;
}
int main()
{
int n = read(), m = read();
for (int i = 1; i <= n; i ++ )
a[i] = read();
build(1, 1, n);
while (m -- )
{
int opt = read();
if (opt == 0)
{
int l0 = read() + 1, r0 = read() + 1;
update(1, l0, r0, 1);
}
else if (opt == 1)
{
int l0 = read() + 1, r0 = read() + 1;
update(1, l0, r0, 2);
}
else if (opt == 2)
{
int l0 = read() + 1, r0 = read() + 1;
update(1, l0, r0, 3);
}
else if (opt == 3)
{
int l0 = read() + 1, r0 = read() + 1;
printf("%d\n", query2(1, l0, r0));
}
else
{
int l0 = read() + 1, r0 = read() + 1;
printf("%d\n", query1(1, l0, r0));
}
}
return 0;
}