洛谷P2572 [SCOI2010]序列操作

题目链接
题意:
三种修改操作
1.set_1:区间置1
2.set_0:区间置0
3.change:区间翻转

两种询问
1.询问区间有多少个1,即为区间求和
2.区间最长1111串(重难点)

解题方法:

不考虑求区间最长1串的询问就是个基本的线段树模板,注意set优先级较大,push_down的时候需保证每次只有一个懒惰标记(tags为set的懒标记,tag=0即为set_1,反之set_0,tagc为change的懒标记),tags下传的时候注意子节点的tagc清0,tagc下传的时候需要维护子节点的tags率先进行set操作,也同时要维护子节点tagc,若子节点tagc=1,两次翻转相当于不翻转,将子节点tagc置为0即可。

关键在于考虑1111…串的情况,由于1111串不能通过左右儿子的最长串来更新,再加上翻转操作时需要最长的0000串的信息,所以为了维护这么一个小小的信息,需要动用大量兵马。

引入下面几个节点信息:

struct Node{
	int l,r,tags,tagc,ls,rs,s; //**基本信息,s为区间和**
	int lenl1,lenr1,maxlen1,lenl0,lenr0,maxlen0;
};//上行分别表示节点左前缀最长11串,右后缀11串,整个区间最长11串,后三个为00串信息,类同。

于是最长11串就很好维护了

void updata(int v){
	int lson=N[v].ls,rson=N[v].rs; 
	N[v].s=N[lson].s+N[rson].s;
	//以下即为最长串的维护
	N[v].lenl1=(N[lson].lenl1==(N[lson].r-N[lson].l+1))?N[lson].lenl1+N[rson].lenl1:N[lson].lenl1;
	N[v].lenr1=(N[rson].lenr1==(N[rson].r-N[rson].l+1))?N[rson].lenr1+N[lson].lenr1:N[rson].lenr1;
	N[v].maxlen1=max(N[lson].lenr1+N[rson].lenl1,max(N[lson].maxlen1,N[rson].maxlen1));
	N[v].lenl0=(N[lson].lenl0==(N[lson].r-N[lson].l+1))?N[lson].lenl0+N[rson].lenl0:N[lson].lenl0;
	N[v].lenr0=(N[rson].lenr0==(N[rson].r-N[rson].l+1))?N[rson].lenr0+N[lson].lenr0:N[rson].lenr0;
	N[v].maxlen0=max(N[lson].lenr0+N[rson].lenl0,max(N[lson].maxlen0,N[rson].maxlen0));
}

再注意一下push_down时对串的维护即可

void push_down(int v){
	if(N[v].tags!=-1){ 
		if(N[v].tags==0){//区间置0
			N[v].s=0;
			N[v].lenl0=N[v].lenr0=N[v].maxlen0=(N[v].r-N[v].l+1);//0前缀后缀都置为区间长度,以此类推
			N[v].lenl1=N[v].lenr1=N[v].maxlen1=0;						
		}
		else{
			N[v].s=N[v].r-N[v].l+1;
			N[v].lenl1=N[v].lenr1=N[v].maxlen1=(N[v].r-N[v].l+1);
			N[v].lenl0=N[v].lenr0=N[v].maxlen0=0;
		}
		if(N[v].l<N[v].r){//下传懒标记
			N[N[v].ls].tagc=N[N[v].rs].tagc=0;//set优先级>change,覆盖懒标记tagc
			N[N[v].ls].tags=N[N[v].rs].tags=N[v].tags;
		}
		N[v].tags=-1;//清除懒标记
	}
	if(N[v].tagc){
		N[v].s=N[v].r-N[v].l+1-N[v].s;
		int tlenl1=N[v].lenl1 , tlenr1=N[v].lenr1 , tmaxlen1=N[v].maxlen1;//翻转所需临时变量
		N[v].lenl1=N[v].lenl0 , N[v].lenr1=N[v].lenr0 , N[v].maxlen1=N[v].maxlen0;
		N[v].lenl0=tlenl1 , N[v].lenr0=tlenr1 , N[v].maxlen0=tmaxlen1;
		if(N[v].l<N[v].r){
			int lson=N[v].ls,rson=N[v].rs;
			if(N[lson].tags!=-1) push_down(lson);//若子节点有tags,先执行set
			if(N[rson].tags!=-1) push_down(rson);
			N[lson].tagc=!N[lson].tagc;//若子节点tagc那么取反
			N[rson].tagc=!N[rson].tagc;
		}
		N[v].tagc=0;
	}
}

上代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<vector>
#include<algorithm>
#define MAXN 100010
using namespace std;
struct Node{int l,r,tags,tagc,ls,rs,s,lenl1,lenr1,maxlen1,lenl0,lenr0,maxlen0;};
struct Data{int l1,r1,maxl1;};
vector<Node> N;
int n,m,a[MAXN];
void updata(int v){
	int lson=N[v].ls,rson=N[v].rs; 
	N[v].s=N[lson].s+N[rson].s;
	N[v].lenl1=(N[lson].lenl1==(N[lson].r-N[lson].l+1))?N[lson].lenl1+N[rson].lenl1:N[lson].lenl1;
	N[v].lenr1=(N[rson].lenr1==(N[rson].r-N[rson].l+1))?N[rson].lenr1+N[lson].lenr1:N[rson].lenr1;
	N[v].maxlen1=max(N[lson].lenr1+N[rson].lenl1,max(N[lson].maxlen1,N[rson].maxlen1));
	N[v].lenl0=(N[lson].lenl0==(N[lson].r-N[lson].l+1))?N[lson].lenl0+N[rson].lenl0:N[lson].lenl0;
	N[v].lenr0=(N[rson].lenr0==(N[rson].r-N[rson].l+1))?N[rson].lenr0+N[lson].lenr0:N[rson].lenr0;
	N[v].maxlen0=max(N[lson].lenr0+N[rson].lenl0,max(N[lson].maxlen0,N[rson].maxlen0));
}
void build_tree(int v){
	if(N[v].l==N[v].r){
		N[v].s=a[N[v].l];
		if(a[N[v].l]==1) {
			N[v].lenl1=N[v].lenr1=N[v].maxlen1=1;
			N[v].lenl0=N[v].lenr0=N[v].maxlen0=0;
		}
		else  {
			N[v].lenl0=N[v].lenr0=N[v].maxlen0=1;
			N[v].lenl1=N[v].lenr1=N[v].maxlen1=0;
		}	
		return;
	}
	int mid=(N[v].l+N[v].r)>>1;
	N.push_back((Node){N[v].l,mid,-1, 0}); N[v].ls=N.size()-1;
	N.push_back((Node){mid+1,N[v].r,-1, 0}); N[v].rs=N.size()-1;
	build_tree(N[v].ls); build_tree(N[v].rs);
	updata(v);
}
void push_down(int v){
	if(N[v].tags!=-1){
		if(N[v].tags==0){
			N[v].s=0;
			N[v].lenl0=N[v].lenr0=N[v].maxlen0=(N[v].r-N[v].l+1);
			N[v].lenl1=N[v].lenr1=N[v].maxlen1=0;
		}
		else{
			N[v].s=N[v].r-N[v].l+1;
			N[v].lenl1=N[v].lenr1=N[v].maxlen1=(N[v].r-N[v].l+1);
			N[v].lenl0=N[v].lenr0=N[v].maxlen0=0;
		}
		if(N[v].l<N[v].r){
			N[N[v].ls].tagc=N[N[v].rs].tagc=0;
			N[N[v].ls].tags=N[N[v].rs].tags=N[v].tags;
		}
		N[v].tags=-1;
	}
	if(N[v].tagc){
		N[v].s=N[v].r-N[v].l+1-N[v].s;
		int tlenl1=N[v].lenl1 , tlenr1=N[v].lenr1 , tmaxlen1=N[v].maxlen1;
		N[v].lenl1=N[v].lenl0 , N[v].lenr1=N[v].lenr0 , N[v].maxlen1=N[v].maxlen0;
		N[v].lenl0=tlenl1 , N[v].lenr0=tlenr1 , N[v].maxlen0=tmaxlen1;
		if(N[v].l<N[v].r){
			int lson=N[v].ls,rson=N[v].rs;
			if(N[lson].tags!=-1) push_down(lson);
			if(N[rson].tags!=-1) push_down(rson);
			N[lson].tagc=!N[lson].tagc;
			N[rson].tagc=!N[rson].tagc;
		}
		N[v].tagc=0;
	}
}
void _set(int v,int l,int r,int p){
	push_down(v);
	if(N[v].l>r||N[v].r<l) return;
	if(N[v].l>=l&&N[v].r<=r){
		N[v].tagc=0;
		N[v].tags=(p==0)?0:1;
		push_down(v);
		return;
	}
	_set(N[v].ls,l,r,p);
	_set(N[v].rs,l,r,p);
	updata(v);
}
void change(int v,int l,int r){
	push_down(v);
	if(N[v].l>r||N[v].r<l) return;
	if(N[v].l>=l&&N[v].r<=r){
		N[v].tagc=1;
		push_down(v);
		return;
	}
	change(N[v].ls,l,r);
	change(N[v].rs,l,r);
	updata(v);
}
int Query_sum(int v,int l,int r){
	if(N[v].l>r||N[v].r<l) return 0;
	push_down(v);
	if(N[v].l>=l&&N[v].r<=r) return N[v].s;
	return Query_sum(N[v].ls,l,r)+Query_sum(N[v].rs,l,r);
}
Data Query_max(int v,int l,int r){
	if(N[v].l>r||N[v].r<l) return (Data){0,0,0};
	push_down(v);
	if(N[v].l>=l&&N[v].r<=r) return (Data){N[v].lenl1,N[v].lenr1,N[v].maxlen1};
	Data lson=Query_max(N[v].ls,l,r),rson=Query_max(N[v].rs,l,r);
	int lmax=(lson.l1==N[N[v].ls].r-N[N[v].ls].l+1)?lson.l1+rson.l1:lson.l1;
	int rmax=(rson.r1==N[N[v].rs].r-N[N[v].rs].l+1)?rson.r1+lson.r1:rson.r1;
	int maxl=max(lson.r1+rson.l1,max(lson.maxl1,rson.maxl1));
	return (Data){lmax,rmax,maxl};
}
int main(){
	scanf("%d%d",&n,&m);
	N.push_back((Node){0, n-1, -1, 0});
	for(int i=0;i<n;i++) scanf("%d",&a[i]);
	build_tree(0);
	while(m--){
		int type,a,b; scanf("%d%d%d",&type,&a,&b);
		switch(type){
			case 0: _set(0,a,b,0); break;
			case 1: _set(0,a,b,1); break;
			case 2: change(0,a,b); break;
			case 3: printf("%d\n",Query_sum(0,a,b)); break;
			case 4: Data ans=Query_max(0,a,b);
					printf("%d\n",ans.maxl1); break;
		}
	}
	return 0;
}

谢谢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值