线段树全家桶,还是挺考验码力的。
注意点:
- 三种 tag 的覆盖关系(隔壁调了半年)
- push_up 和 push_down 的更新细节
- query2 的去最值细节(我举得我的方法蛮好的)。
总之坑点还是蛮多的。
code
#include<bits/stdc++.h>
#define N 200005
#define ls(p) p<<1
#define rs(p) p<<1|1
using namespace std;
int read(){
int x=0,w=1;
char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return x*w;
}
int n,m;
int a[N];
struct Seg{int lc,rc,lm[2],rm[2],sum,maxn[2],tag,len;}tree[N<<2];
void push_up(int p){
tree[p].lm[1]=tree[ls(p)].lm[1];tree[p].lm[0]=tree[ls(p)].lm[0];
tree[p].rm[1]=tree[rs(p)].rm[1];tree[p].rm[0]=tree[rs(p)].rm[0];
if(tree[ls(p)].sum==0) tree[p].lm[0]=tree[ls(p)].len+tree[rs(p)].lm[0];
if(tree[ls(p)].sum==tree[ls(p)].len) tree[p].lm[1]=tree[ls(p)].len+tree[rs(p)].lm[1];
if(tree[rs(p)].sum==0) tree[p].rm[0]=tree[rs(p)].len+tree[ls(p)].rm[0];
if(tree[rs(p)].sum==tree[rs(p)].len) tree[p].rm[1]=tree[rs(p)].len+tree[ls(p)].rm[1];
tree[p].maxn[1]=max(tree[ls(p)].rm[1]+tree[rs(p)].lm[1],max(tree[ls(p)].maxn[1],tree[rs(p)].maxn[1]));
tree[p].maxn[0]=max(tree[ls(p)].rm[0]+tree[rs(p)].lm[0],max(tree[ls(p)].maxn[0],tree[rs(p)].maxn[0]));
tree[p].lc=tree[ls(p)].lc;tree[p].rc=tree[rs(p)].rc;
tree[p].sum=tree[ls(p)].sum+tree[rs(p)].sum;
}
void work1(int p){
tree[p].lc=tree[p].rc=0;
tree[p].maxn[1]=0;tree[p].maxn[0]=tree[p].len;tree[p].sum=0;
tree[p].lm[0]=tree[p].rm[0]=tree[p].len;
tree[p].lm[1]=tree[p].rm[1]=0;
tree[p].tag=1;
}
void work2(int p){
tree[p].lc=tree[p].rc=1;
tree[p].maxn[1]=tree[p].len;tree[p].maxn[0]=0;tree[p].sum=tree[p].len;
tree[p].lm[1]=tree[p].rm[1]=tree[p].len;
tree[p].lm[0]=tree[p].rm[0]=0;
tree[p].tag=2;
}
void work3(int p){
tree[p].lc^=1;tree[p].rc^=1;
swap(tree[p].maxn[1],tree[p].maxn[0]);
swap(tree[p].lm[1],tree[p].lm[0]); swap(tree[p].rm[0],tree[p].rm[1]);
tree[p].sum=tree[p].len-tree[p].sum;
if(tree[p].tag==1) tree[p].tag=2;
else if(tree[p].tag==2) tree[p].tag=1;
else if(tree[p].tag==0) tree[p].tag=3;
else tree[p].tag=0;
}
void push_down(int p){
if(!tree[p].tag) return ;
if(tree[p].tag==1)work1(ls(p)),work1(rs(p));
else if(tree[p].tag==2) work2(ls(p)),work2(rs(p));
else if(tree[p].tag==3) work3(ls(p)),work3(rs(p));
tree[p].tag=0;
}
void build(int p,int l,int r){
tree[p].len=r-l+1;
if(l==r){
tree[p].lc=tree[p].rc=a[l];
tree[p].lm[a[l]]=tree[p].rm[a[l]]=tree[p].maxn[a[l]]=1;
if(a[l]==1) tree[p].sum=1;
return ;
}
int mid=(l+r)>>1;
build(ls(p),l,mid);build(rs(p),mid+1,r);
push_up(p);
}
void update1(int p,int l,int r,int L,int R){
if(L<=l&&r<=R){work1(p);return ;}
int mid=(l+r)>>1;
push_down(p);
if(mid>=L) update1(ls(p),l,mid,L,R);
if(mid<R) update1(rs(p),mid+1,r,L,R);
push_up(p);
}
void update2(int p,int l,int r,int L,int R){
if(L<=l&&r<=R){work2(p);return ;}
int mid=(l+r)>>1;
push_down(p);
if(mid>=L) update2(ls(p),l,mid,L,R);
if(mid<R) update2(rs(p),mid+1,r,L,R);
push_up(p);
}
void update3(int p,int l,int r,int L,int R){
if(L<=l&&r<=R){work3(p);return ;}
int mid=(l+r)>>1;
push_down(p);
if(mid>=L) update3(ls(p),l,mid,L,R);
if(mid<R) update3(rs(p),mid+1,r,L,R);
push_up(p);
}
int query1(int p,int l,int r,int L,int R){
if(L<=l&&r<=R) return tree[p].sum;
int mid=(l+r)>>1,res=0;
push_down(p);
if(mid>=L) res+=query1(ls(p),l,mid,L,R);
if(mid<R) res+=query1(rs(p),mid+1,r,L,R);
return res;
}
int query2(int p,int l,int r,int L,int R){
if(L<=l&&r<=R) return tree[p].maxn[1];
int mid=(l+r)>>1,res1=0,res2=0,res3=0;
push_down(p);
if(mid>=L) res1=query2(ls(p),l,mid,L,R);
if(mid<R) res2=query2(rs(p),mid+1,r,L,R);
if(tree[ls(p)].rc==tree[rs(p)].lc&&tree[ls(p)].rc==1)
res3=min(tree[ls(p)].rm[1],res1)+min(tree[rs(p)].lm[1],res2);
return max(res1,max(res3,res2));
}
signed main(){
//freopen("111.out","r",stdin);
//freopen("work.out","w",stdout);
n=read();m=read();
for(int i=1;i<=n;++i) a[i]=read();
build(1,1,n);
for(int i=1;i<=m;++i){
int opt=read(),l=read(),r=read();l++;r++;
if(opt==0) update1(1,1,n,l,r);
else if(opt==1) update2(1,1,n,l,r);
else if(opt==2) update3(1,1,n,l,r);
else if(opt==3) printf("%d\n",query1(1,1,n,l,r));
else printf("%d\n",query2(1,1,n,l,r));
//cout<<query2(1,1,n,5,9)<<endl;
}
return 0;
}
个人觉得还是挺优美的哈。