HDU - 3397 Sequence operation (线段树,区间修改,亦或,查询,以及最长连续的1)

有5个操作,

0  区间全部置为0

1 区间全部置为1

2 区间的值取反,1 变0 ,0变1,

3 求区间1 的个数。

4 求区间连续最长的1.

思路:

lazy标记, 有 -1,0,1,2, 四种标记,

-1 是什么都没有,

0,1 算是一种操作,区间修改,

2 是一种操作,亦或。

因为亦或这个操作。我们存一下1 的所有数据,0的所有数据,便于以后交换。

我们要考虑一下优先级的问题,

1,无论当前节点之前是什么标记,现在给它 0,或者1 的标记,那就直接覆盖就好。

2,当前节点之前是0 或 1 标记,现在给他 2 标记,那么我们就把之前的标记亦或一下,

3,当前节点之前是 2 或者 -1,我们这个时候就要交换0 的数据和1 的数据,

然后lazy标记,之前为-1现在为2,之前为2现在为-1,因为两次亦或相当于不变。

#include <bits/stdc++.h>
#define mem(x,v) memset(x,v,sizeof(x)) 
#define rep(i,a,b)  for (int i = a; i < b; i++)
#define per(i,a,b)  for (int i = a; i > b; i--)
using namespace std;
typedef long long LL;
const double EPS = 1e-10;
const int INF = 0x3f3f3f3f;
const int N = 1e5+100;
struct segtree{
	int l,r,a,b;
	int w,ll1,rr1,ll,ll0,rr0,rr; // w 是区间和,ll1,ll0 从左1 或 0 的个数,rr1,rr0 从右的个数,ll,rr,区间最长1 或者 0 的个数。
	int lazy; // lazy标记,0,1,2,-1,四种标记。
	int calc_mid(){
		return (a + b)/2;
	}
	int calc_len(){
		return (b - a);
	}
	void calc_swap(){ //交换。
		swap(ll1,ll0);
		swap(rr1,rr0);
		swap(ll,rr);
		return;
	}
}f[N*2];
int n,c[N],t,m;

void push_up(int p){
	f[p].w = f[f[p].l].w + f[f[p].r].w;
	f[p].ll1 = f[f[p].l].ll1; if (f[f[p].l].ll1 == f[f[p].l].calc_len()) f[p].ll1 += f[f[p].r].ll1;
	f[p].rr1 = f[f[p].r].rr1; if (f[f[p].r].rr1 == f[f[p].r].calc_len()) f[p].rr1 += f[f[p].l].rr1;
	f[p].ll = max(f[f[p].l].ll,max(f[f[p].r].ll,f[f[p].l].rr1+f[f[p].r].ll1));

	f[p].ll0 = f[f[p].l].ll0; if (f[f[p].l].ll0 == f[f[p].l].calc_len()) f[p].ll0 += f[f[p].r].ll0;
	f[p].rr0 = f[f[p].r].rr0; if (f[f[p].r].rr0 == f[f[p].r].calc_len()) f[p].rr0 += f[f[p].l].rr0;
	f[p].rr = max(f[f[p].l].rr,max(f[f[p].r].rr,f[f[p].l].rr0+f[f[p].r].ll0));
	return;
}
void push_down(int p){ 
	f[p].w = f[p].calc_len() * f[p].lazy;
	f[p].ll1 = f[p].rr1 = f[p].ll = f[p].lazy * f[p].calc_len();
	f[p].ll0 = f[p].rr0 = f[p].rr = f[p].calc_len() - f[p].ll;
	return;
}

void push_downxor(int p){
	if (f[p].lazy == -1) return;
	if (f[p].lazy == 2) { //如果是 2,要考虑当前节点的左右儿子的标记是什么。
		if (f[f[p].l].lazy == 0 || f[f[p].l].lazy == 1) f[f[p].l].lazy ^= 1,push_down(f[p].l);
		if (f[f[p].r].lazy == 0 || f[f[p].r].lazy == 1) f[f[p].r].lazy ^= 1,push_down(f[p].r);
		if (f[f[p].l].lazy == -1 || f[f[p].l].lazy == 2){
			f[f[p].l].calc_swap();
			f[f[p].l].w = f[f[p].l].calc_len() - f[f[p].l].w;
			f[f[p].l].lazy = 1 - f[f[p].l].lazy;
		}
		if (f[f[p].r].lazy == -1 || f[f[p].r].lazy == 2){
			f[f[p].r].calc_swap();
			f[f[p].r].w = f[f[p].r].calc_len() - f[f[p].r].w;
			f[f[p].r].lazy = 1 - f[f[p].r].lazy;
		}
	} else { //lazy标记,向下传递,如果是 0,或者 1. 直接向下传递。
		f[f[p].l].lazy = f[f[p].r].lazy = f[p].lazy;
		push_down(f[p].l);
		push_down(f[p].r);
	}

	f[p].lazy = -1;
	return;

}
void build(int p, int a, int b){
	f[p].a = a; f[p].b = b; f[p].lazy = -1;
	f[p].ll1 = f[p].rr1 = f[p].ll = f[p].ll0 = f[p].rr0 = f[p].rr = 0;
	if (a + 1 == b){
		f[p].w = c[a]; 
		if (c[a] == 0) f[p].ll0 = f[p].rr0 = f[p].rr = 1; else
		f[p].ll1 = f[p].rr1 = f[p].ll = 1;
		return;
	}
	int m = f[p].calc_mid();
	t++; f[p].l = t; build(t,a,m);
	t++; f[p].r = t; build(t,m,b);
	push_up(p);
}
void Insert(int p, int x, int y, int z){
	if (x <= f[p].a && y >= f[p].b - 1){
		if (z == 2) { //如果z为2,要考虑当前的标记是什么。
			if (f[p].lazy == 1 || f[p].lazy == 0){ //如果是 1 或者 0, 亦或就是直接取他们的相反的值,
				f[p].lazy = f[p].lazy ^ 1;
				push_down(p);
			} else{ //如果不是 1 或者 0, 就直接交换 我们储存的 0 和1 的数据,如果本身标记 是-1,标记2,。本事标记是2,则标记-1
				f[p].calc_swap();
				f[p].w = f[p].calc_len() - f[p].w;
				f[p].lazy = 1 - f[p].lazy;
			}
		} else{ //如果z是1 或者0,那就直接覆盖就好了。
			f[p].lazy = z; push_down(p);
		}
		return;
	}
	push_downxor(p);
	int m = f[p].calc_mid();
	if (x < m) Insert(f[p].l, x, y, z);
	if (y >= m) Insert(f[p].r, x, y, z);
	push_up(p);
	return;
}

int Query(int p, int x, int y, int z){
	int ans = 0;
	if (x <= f[p].a && y >= f[p].b-1){
		if (z == 3) return f[p].w; else return f[p].ll; //根据op 的值,来返回不同的类型。
	}
	push_downxor(p);
	int m = f[p].calc_mid();
	if (z == 3){
		if (x < m) ans += Query(f[p].l,x,y,z);//这个地方找区间和。
		if (y >= m) ans += Query(f[p].r,x,y,z);
	} else{
		if (x < m) ans = max(ans,Query(f[p].l,x,y,z));
		if (y >= m) ans = max(ans,Query(f[p].r,x,y,z));
		if (x < m && y >= m) { 
			int dx = min(f[f[p].l].rr1,f[f[p].l].b - x);
			int dy = min(f[f[p].r].ll1,y - f[f[p].r].a + 1); //这个地方求最长连续的一。
			ans = max(ans,dx+dy);
		}
	}
	return ans;
}
int main(){
	int T; cin>>T;
	while(T--){
		scanf("%d%d",&n,&m);
		rep(i,1,n+1) scanf("%d",&c[i]);
		t = 1; build(1,1,n+1);
		while(m--){
			int op,x,y;  
			scanf("%d%d%d",&op,&x,&y);
			x++; y++;
			if (op < 3) Insert(1,x,y,op); else printf("%d\n",Query(1,x,y,op)); 
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/kidsummer/article/details/81589726