题目链接
题意:
三种修改操作
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;
}
谢谢