有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;
}