线段树全家桶,还是挺考验码力的。

注意点:

  • 三种 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;
}

个人觉得还是挺优美的哈。