/********************************************** 题目大意: 0 a b将区间[a,b]所有数全部变成0 1 a b将区间[a,b]所有数全部变成1 2 a b将区间[a,b]中所有数0 1互换,0变1,1变0 3 a b输出区间[a,b]中1的个数 4 a b输出区间[a,b]中最长连续1的个数 算法分析: 涉及到线段树的多种操作; 0,1两种操作可以合并到一起写; 0,1互换即线段树的异或操作; 查询区间最长连续1个数的过程中; maxl=[l,m]上最长连续1个数; maxl=[m+1,r]上最长连续1的个数; maxm=min(m-l+1,左孩子的rs)+min(r-m,右孩子的ls); 结果应该是这三个中的最大值,即max(maxl,maxr,maxm); 其中查询操作和pku3667类似; ***********************************************/ #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<climits> #include<algorithm> using namespace std; #define L l,m,u<<1 #define R m+1,r,u<<1|1 const int N =100010; struct node { int l,r; int ls,ms,rs;//ms存储最长连续1的数量 int flag;//01状态 int total;//区间1的总数 } t[N*3]; int len(int u) { return t[u].r-t[u].l+1; } int mid(int u) { return (t[u].l+t[u].r)>>1; } void sets(int u,int x) { t[u].ls=t[u].ms=t[u].rs=t[u].total=x*(t[u].r-t[u].l+1); t[u].flag=x; } void build(int l,int r,int u) { t[u].l=l; t[u].r=r; t[u].ls=t[u].rs=t[u].ms=t[u].total=t[u].flag=0; if(l==r) return; int m=mid(u); build(L); build(R); } void PushUp(int u)//把当前结点的信息更新到父结点 { t[u].flag=(t[u<<1].flag==t[u<<1|1].flag?t[u<<1].flag:-1);//更新状态 t[u].ls=t[u<<1].ls+((t[u<<1].ls==len(u<<1))?t[u<<1|1].ls:0);//更新左 t[u].rs=t[u<<1|1].rs+((t[u<<1|1].rs==len(u<<1|1))?t[u<<1].rs:0);//更新右 t[u].ms=max(t[u<<1].rs+t[u<<1|1].ls,max(t[u<<1].ms,t[u<<1|1].ms));//更新整体 t[u].total=t[u<<1].total+t[u<<1|1].total;//更新1的总数 } void update(int l,int r,int u,int x)//更新区间[l,r]0、1状态 { if(t[u].flag==x) return; if(t[u].l==l&&t[u].r==r) { sets(u,x); return; } if(t[u].flag>=0) { sets(u<<1,t[u].flag); sets(u<<1|1,t[u].flag); t[u].flag=-1; } int m=mid(u); if(r<=m) { update(l,r,u<<1,x); } else if(l>m) { update(l,r,u<<1|1,x); } else { update(L,x); update(R,x); } PushUp(u); } void swap(int l,int r,int u)//[l,r]0、1交换 { if(t[u].l>=l&&t[u].r<=r&&(t[u].flag==0||t[u].flag==1)) { int x=t[u].flag^1; sets(u,x); return; } if(t[u].flag>=0) { sets(u<<1,t[u].flag); sets(u<<1|1,t[u].flag); } int m=mid(u); if(r<=m) { swap(l,r,u<<1); } else if(l>m) { swap(l,r,u<<1|1); } else { swap(L); swap(R); } PushUp(u); } int find1(int l,int r,int u)//找区间[l,r]内的1的个数 { if(t[u].l==l&&t[u].r==r) { return t[u].total; } if(t[u].flag>=0) { sets(u<<1,t[u].flag); sets(u<<1|1,t[u].flag); } int m=mid(u); if(r<=m) { return find1(l,r,u<<1); } else if(l>m) { return find1(l,r,u<<1|1); } else { return find1(L)+find1(R); } } int find2(int l,int r,int u)//找区间[l,r]内最长连续1的个数 { if(t[u].l==l&&t[u].r==r) { return t[u].ms; } if(t[u].flag>=0) { sets(u<<1,t[u].flag); sets(u<<1|1,t[u].flag); } int m=mid(u); if(r<=m) { return find2(l,r,u<<1); } else if(l>m) { return find2(l,r,u<<1|1); } else { int maxl=find2(L); int maxr=find2(R); int maxm=min(m-l+1,t[u<<1].rs)+min(r-m,t[u<<1|1].ls); return max(maxm,max(maxl,maxr)); } } int main() { //freopen("C:\\Users\\Administrator\\Desktop\\kd.txt","r",stdin); int t; scanf("%d",&t); while(t--) { int n,m; scanf("%d%d",&n,&m); build(0,n-1,1); for(int i=0; i<n; i++) { int x; scanf("%d",&x); if(x!=0) update(i,i,1,x); } for(int i=0; i<m; i++) { int op,a,b; scanf("%d%d%d",&op,&a,&b); if(op==0||op==1) update(a,b,1,op); else if(op==2) swap(a,b,1); else if(op==3) printf("%d\n",find1(a,b,1)); else if(op==4) printf("%d\n",find2(a,b,1)); } } return 0; }