[Luogu] P2572 [SCOI2010]序列操作

\(Link\)

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;
}
posted @ 2020-11-19 21:26  andysj  阅读(138)  评论(0编辑  收藏  举报