题意:
给你一个01的串,有五种操作,第一种,将某个区间覆盖成0,第二种,将某个区间覆盖成1,第三种,将某个区间取反(即0变1,1变0),第四种,问某个区间1的个数,第五种,问某个区间最长连续的1的长度
思路:
超级超级超级麻烦的区间更新
首先,对于1,2,4操作,都是基础线段树的操作,5是基础区间更新的操作,但是此时多了一个3操作,导致写起来直接麻烦了很多
首先因为有异或和区间覆盖,我们可以维护lazy和Xor来节省时间,而因为我们需要取反,并且要迅速统计区间连续1最长的长度,我们就需要同时维护1和0的情况,因为只有在都维护的时候,我们才能快速处理取反操作(取反的时候我们只要交换0和1的数据即可)
说的很简单,但是代码量惊人,写起来贼麻烦,要处理好覆盖和异或的优先级,并且在处理lazy的时候,更新lsum,rsum,msum要处处注意细节
错误及反思:
虽然只wa了一次,但是找bug找了好久,强烈推荐dicuss里面老哥的数据,真的很管用
代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int N = 100010;
int n,T,k,op,ta,tb,t;
int segtree[N<<2][2],lsum[N<<2][2],rsum[N<<2][2],msum[N<<2][2],lazy[N<<2],Xor[N<<2];
void pushdown(int l,int r,int rt)
{
if(lazy[rt]!=-1)
{
int m=(l+r)/2;
t=lazy[rt];
lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];
Xor[rt<<1]=Xor[rt<<1|1]=0;
segtree[rt<<1][t]=lsum[rt<<1][t]=rsum[rt<<1][t]=msum[rt<<1][t]=m-l+1;
segtree[rt<<1][t^1]=lsum[rt<<1][t^1]=rsum[rt<<1][t^1]=msum[rt<<1][t^1]=0;
segtree[rt<<1|1][t]=lsum[rt<<1|1][t]=rsum[rt<<1|1][t]=msum[rt<<1|1][t]=r-m;
segtree[rt<<1|1][t^1]=lsum[rt<<1|1][t^1]=rsum[rt<<1|1][t^1]=msum[rt<<1|1][t^1]=0;
lazy[rt]=-1;
}
else if(Xor[rt])
{
if(lazy[rt<<1]!=-1)
{
lazy[rt<<1]++;
lazy[rt<<1]%=2;
}
else{
Xor[rt<<1]++;
Xor[rt<<1]%=2;
}
if(lazy[rt<<1|1]!=-1)
{
lazy[rt<<1|1]++;
lazy[rt<<1|1]%=2;
}
else{
Xor[rt<<1|1]++;
Xor[rt<<1|1]%=2;
}
Xor[rt]=0;
swap(segtree[rt<<1][0],segtree[rt<<1][1]);
swap(lsum[rt<<1][0],lsum[rt<<1][1]);
swap(rsum[rt<<1][0],rsum[rt<<1][1]);
swap(msum[rt<<1][0],msum[rt<<1][1]);
swap(segtree[rt<<1|1][0],segtree[rt<<1|1][1]);
swap(lsum[rt<<1|1][0],lsum[rt<<1|1][1]);
swap(rsum[rt<<1|1][0],rsum[rt<<1|1][1]);
swap(msum[rt<<1|1][0],msum[rt<<1|1][1]);
}
}
void pushup(int l,int r,int rt)
{
int m=(l+r)/2;
segtree[rt][0]=segtree[rt<<1][0]+segtree[rt<<1|1][0];
segtree[rt][1]=segtree[rt<<1][1]+segtree[rt<<1|1][1];
if(lsum[rt<<1][0]==m-l+1)
lsum[rt][0]=lsum[rt<<1][0]+lsum[rt<<1|1][0];
else lsum[rt][0]=lsum[rt<<1][0];
if(rsum[rt<<1|1][0]==r-m)
rsum[rt][0]=rsum[rt<<1][0]+rsum[rt<<1|1][0];
else rsum[rt][0]=rsum[rt<<1|1][0];
msum[rt][0]=max(rsum[rt<<1][0]+lsum[rt<<1|1][0],max(msum[rt<<1][0],msum[rt<<1|1][0]));
if(lsum[rt<<1][1]==m-l+1)
lsum[rt][1]=lsum[rt<<1][1]+lsum[rt<<1|1][1];
else lsum[rt][1]=lsum[rt<<1][1];
if(rsum[rt<<1|1][1]==r-m)
rsum[rt][1]=rsum[rt<<1][1]+rsum[rt<<1|1][1];
else rsum[rt][1]=rsum[rt<<1|1][1];
msum[rt][1]=max(rsum[rt<<1][1]+lsum[rt<<1|1][1],max(msum[rt<<1][1],msum[rt<<1|1][1]));
}
void build(int l,int r,int rt)
{
if(l==r)
{
scanf("%d",&t);
segtree[rt][t]=lsum[rt][t]=rsum[rt][t]=msum[rt][t]=1;
segtree[rt][t^1]=lsum[rt][t^1]=rsum[rt][t^1]=msum[rt][t^1]=0;
return ;
}
int m=(l+r)/2;
build(lson);
build(rson);
pushup(l,r,rt);
}
void change1(int L,int R,int v,int l,int r,int rt)
{
if(L<=l&&R>=r)
{
lazy[rt]=v;
Xor[rt]=0;
segtree[rt][v]=lsum[rt][v]=rsum[rt][v]=msum[rt][v]=r-l+1;
segtree[rt][v^1]=lsum[rt][v^1]=rsum[rt][v^1]=msum[rt][v^1]=0;
return ;
}
pushdown(l,r,rt);
int m=(l+r)/2;
if(L<=m) change1(L,R,v,lson);
if(R>m) change1(L,R,v,rson);
pushup(l,r,rt);
}
void change2(int L,int R,int l,int r,int rt)
{
if(L<=l&&R>=r)
{
if(lazy[rt]!=-1)
{
lazy[rt]++;
lazy[rt]%=2;
}
else{
Xor[rt]++;
Xor[rt]%=2;
}
swap(segtree[rt][0],segtree[rt][1]);
swap(lsum[rt][0],lsum[rt][1]);
swap(rsum[rt][0],rsum[rt][1]);
swap(msum[rt][0],msum[rt][1]);
return ;
}
pushdown(l,r,rt);
int m=(l+r)/2;
if(L<=m) change2(L,R,lson);
if(R>m) change2(L,R,rson);
pushup(l,r,rt);
}
int query1(int L,int R,int l,int r,int rt)
{
if(L<=l&&R>=r)
return segtree[rt][1];
pushdown(l,r,rt);
int m=(l+r)/2;
int ans=0;
if(L<=m) ans+=query1(L,R,lson);
if(R>m) ans+=query1(L,R,rson);
pushup(l,r,rt);
return ans;
}
int query2(int L,int R,int l,int r,int rt)
{
if(L<=l&&R>=r)
return msum[rt][1];
pushdown(l,r,rt);
int m=(l+r)/2;
if(R<=m) return query2(L,R,lson);
if(L>m) return query2(L,R,rson);
int ans=max(query2(L,R,lson),query2(L,R,rson));
ans=max(ans,min(m-L+1,rsum[rt<<1][1])+min(R-m,lsum[rt<<1|1][1]));
pushup(l,r,rt);
return ans;
}
int main()
{
scanf("%d",&T);
while(T--)
{
memset(lazy,-1,sizeof(lazy));
memset(Xor,0,sizeof(Xor));
scanf("%d%d",&n,&k);
build(0,n-1,1);
while(k--)
{
scanf("%d%d%d",&op,&ta,&tb);
if(op==0) change1(ta,tb,0,0,n-1,1);
else if(op==1) change1(ta,tb,1,0,n-1,1);
else if(op==2) change2(ta,tb,0,n-1,1);
else if(op==3) printf("%d\n",query1(ta,tb,0,n-1,1));
else printf("%d\n",query2(ta,tb,0,n-1,1));
}
}
}