洛谷2572 【SCOI2010】序列操作(线段树)

传送门

【题目分析】

线段树大板题,主要就是靠码量和debug能力。。。

既然涉及到区间取反,那么同时记录0和1的信息。

对于0,1操作,打上区间覆盖标记即可。

对于2操作,打区间取反标记,但注意如果该区间已经打了区间覆盖标记,那么其实取反标记作用只是将0改为1,所以可以直接将区间取反标记赋为0,覆盖标记取亦或。

对于3操作,直接统计即可。

对于操作4,考虑两种情况:1.当前区间maxmid为区间长,那么可以取左右两区间的左右最长。2.否则直接取左边最长,右边最长再与中间作比较取最大值即可。

代码细节很多,调起来很难受qwq

【代码~】

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+10;
const int INF=0x3f3f3f3f;

int n,q,ans,maxx;
int a[MAXN];
struct Tree{
	int l,r;
	int maxl[2],maxr[2],mmid[2];
	int cnt[2];
	int cov;
	int rev;
}tr[MAXN<<2];

int Read(){
	int i=0,f=1;
	char c;
	for(c=getchar();(c>'9'||c<'0')&&c!='-';c=getchar());
	if(c=='-')
	  f=-1,c=getchar();
	for(;c>='0'&&c<='9';c=getchar())
	  i=(i<<3)+(i<<1)+c-'0';
	return i*f;
}

void push_up(int root){
	int mid=tr[root].l+tr[root].r>>1;
	for(int i=0;i<2;++i){
		tr[root].cnt[i]=tr[root<<1].cnt[i]+tr[root<<1|1].cnt[i];
		tr[root].maxl[i]=tr[root<<1].maxl[i],tr[root].maxr[i]=tr[root<<1|1].maxr[i];
		if(tr[root<<1].maxl[i]==mid-tr[root].l+1)
		  tr[root].maxl[i]+=tr[root<<1|1].maxl[i];
		if(tr[root<<1|1].maxr[i]==tr[root].r-mid)
		  tr[root].maxr[i]+=tr[root<<1].maxr[i];
		tr[root].mmid[i]=max(tr[root<<1].mmid[i],max(tr[root<<1|1].mmid[i],tr[root<<1].maxr[i]+tr[root<<1|1].maxl[i]));
	}
}

void push_cov(int root,int key){
	tr[root].cov=key;
	for(int i=0;i<2;++i){
		tr[root].cnt[i]=tr[root].maxl[i]=tr[root].maxr[i]=tr[root].mmid[i]=(key==i)?(tr[root].r-tr[root].l+1):0;
	}
}

void push_rev(int root){
	tr[root].rev^=1;
	swap(tr[root].maxl[0],tr[root].maxl[1]);
	swap(tr[root].maxr[0],tr[root].maxr[1]);
	swap(tr[root].mmid[0],tr[root].mmid[1]);
	swap(tr[root].cnt[0],tr[root].cnt[1]);
	if(tr[root].cov!=-1){
		tr[root].rev=0;
		tr[root].cov^=1;
	}
}

void push_down(int root){
	if(tr[root].cov!=-1){
		push_cov(root<<1,tr[root].cov);
		push_cov(root<<1|1,tr[root].cov);
		tr[root].cov=-1;
		tr[root].rev=0;
	}
	if(tr[root].rev){
		push_rev(root<<1);
		push_rev(root<<1|1);
		tr[root].rev=0;
	}
}

void build(int root,int l,int r){
	tr[root].l=l,tr[root].r=r;
	tr[root].cov=-1;
	if(l==r){
		for(int i=0;i<2;++i){
			tr[root].maxl[i]=tr[root].maxr[i]=tr[root].mmid[i]=(a[l]==i)?1:0;
			tr[root].cnt[i]=(a[l]==i)?1:0;
		}
		return ;
	}
	int mid=l+r>>1;
	build(root<<1,l,mid);
	build(root<<1|1,mid+1,r);
	push_up(root);
}

void update_cov(int root,int l,int r,int L,int R,int key){
	if(l>R||r<L)
	  return ;
	if(L<=l&&r<=R){
		push_cov(root,key);
		return ;
	}
	push_down(root);
	int mid=l+r>>1;
	if(R<=mid)
	  update_cov(root<<1,l,mid,L,R,key);
	else{
		if(L>mid)
		  update_cov(root<<1|1,mid+1,r,L,R,key);
		else
		  update_cov(root<<1,l,mid,L,mid,key),update_cov(root<<1|1,mid+1,r,mid+1,R,key);
	}
	push_up(root);
}

void update_rev(int root,int l,int r,int L,int R){
	if(l>R||r<L)
	  return ;
	if(L<=l&&r<=R){
		push_rev(root);
		return ;
	}
	push_down(root);
	int mid=l+r>>1;
	if(R<=mid)
	  update_rev(root<<1,l,mid,L,R);
	else{
		if(L>mid)
		  update_rev(root<<1|1,mid+1,r,L,R);
		else
		  update_rev(root<<1,l,mid,L,mid),update_rev(root<<1|1,mid+1,r,mid+1,R);
	}
	push_up(root);
}

int query_tot(int root,int l,int r,int L,int R){
	if(l>R||r<L)
	  return 0;
	if(L<=l&&r<=R){
		return tr[root].cnt[1];
	}
	push_down(root);
	int mid=l+r>>1;
	if(R<=mid)
	  return query_tot(root<<1,l,mid,L,R);
	else{
		if(L>mid)
		  return query_tot(root<<1|1,mid+1,r,L,R);
		else
		  return query_tot(root<<1,l,mid,L,mid)+query_tot(root<<1|1,mid+1,r,mid+1,R);
	}
}


void query_max(int root,int l,int r,int L,int R){
	if(tr[root].l==L&&tr[root].r==R){
		ans=max(ans,tr[root].mmid[1]);
		ans=max(ans,maxx+tr[root].maxl[1]);
		if(tr[root].cnt[1]==tr[root].r-tr[root].l+1)
		  maxx+=tr[root].cnt[1];
		else
		  maxx=tr[root].maxr[1];
		return ;
	}
	push_down(root);
	int mid=l+r>>1;
	if(R<=mid)
	  query_max(root<<1,l,mid,L,R);
	else{
		if(L>mid)
		  query_max(root<<1|1,mid+1,r,L,R);
		else
		  query_max(root<<1,l,mid,L,mid),query_max(root<<1|1,mid+1,r,mid+1,R);
	}
}

int main(){
	n=Read(),q=Read();
	for(int i=1;i<=n;++i)
	  a[i]=Read();
	build(1,1,n);
	while(q--){
		int cz=Read(),l=Read()+1,r=Read()+1;
		switch(cz){
			case 0:{
		  	    update_cov(1,1,n,l,r,0);
		  	    break;
		  	}
			case 1:{
			  	update_cov(1,1,n,l,r,1);
			  	break;
			}
			case 2:{
			  	update_rev(1,1,n,l,r);
			  	break;
			}
			case 3:{
			  	cout<<query_tot(1,1,n,l,r)<<'\n';
			  	break;
			}
			case 4:{
			    maxx=ans=0;
				query_max(1,1,n,l,r);
				cout<<ans<<'\n';
				break;
			}
		}
	}
	return 0;
}

 

转载于:https://www.cnblogs.com/Ishtar/p/10291861.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值