[SCOI2010]序列操作
Posted ah2002
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[SCOI2010]序列操作相关的知识,希望对你有一定的参考价值。
操作0、1:区间赋值
操作2:区间异或
操作3:区间求和
操作4:区间最长连续段
我们用线段树打lazy标记的方式维护:某段区间从左向右和从右向左延伸的0和1的长度、某段区间内0和1的最长长度、区间和。
然后分类讨论pushdown与pushup即可
#include"cstdio"
#include"cstring"
#include"iostream"
#include"algorithm"
using namespace std;
const int MAXN=1<<17;
int n,m;
int a[MAXN];
int lef[2][MAXN<<1],rig[2][MAXN<<1],mx[2][MAXN<<1];
int sm[MAXN<<1],tag[MAXN<<1],chg[MAXN<<1];
inline int read()
{
int x=0;char ch=getchar();
while(ch<‘0‘||‘9‘<ch) ch=getchar();
while(‘0‘<=ch&&ch<=‘9‘) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x;
}
inline void pushup(int k,int l,int r)
{
if(l==r) return;
int i=k<<1,mid=l+r>>1;
lef[0][k]=lef[0][i]==mid-l+1?lef[0][i]+lef[0][i|1]:lef[0][i];
lef[1][k]=lef[1][i]==mid-l+1?lef[1][i]+lef[1][i|1]:lef[1][i];
rig[0][k]=rig[0][i|1]==r-mid?rig[0][i|1]+rig[0][i]:rig[0][i|1];
rig[1][k]=rig[1][i|1]==r-mid?rig[1][i|1]+rig[1][i]:rig[1][i|1];
mx[0][k]=max(rig[0][i]+lef[0][i|1],max(mx[0][i],mx[0][i|1]));
mx[1][k]=max(rig[1][i]+lef[1][i|1],max(mx[1][i],mx[1][i|1]));
sm[k]=sm[i]+sm[i|1];
return;
}
void build(int k,int l,int r)
{
chg[k]=-1;
if(l==r){
if(a[l]) sm[k]=1;
lef[a[l]][k]=rig[a[l]][k]=mx[a[l]][k]=1;
return;
}int i=k<<1,mid=l+r>>1;
build(i,l,mid);build(i|1,mid+1,r);
pushup(k,l,r);
return;
}
void pushdown(int k,int l,int r)
{
if(l==r||(!tag[k]&&chg[k]==-1)) return;
int i=k<<1,mid=l+r>>1;
if(tag[k]){
if(chg[i]!=-1) chg[i]^=1;
if(chg[i|1]!=-1) chg[i|1]^=1;
tag[i]^=1;tag[i|1]^=1;
sm[i]=mid-l+1-sm[i];sm[i|1]=r-mid-sm[i|1];
swap(lef[0][i],lef[1][i]),swap(rig[0][i],rig[1][i]),swap(mx[0][i],mx[1][i]);
swap(lef[0][i|1],lef[1][i|1]),swap(rig[0][i|1],rig[1][i|1]),swap(mx[0][i|1],mx[1][i|1]);
tag[k]=0;
}if(chg[k]!=-1){
tag[i]=tag[i|1]=0;chg[i]=chg[i|1]=chg[k];
sm[i]=chg[k]?mid-l+1:0;sm[i|1]=chg[k]?r-mid:0;
lef[chg[k]][i]=rig[chg[k]][i]=mx[chg[k]][i]=mid-l+1;
lef[chg[k]^1][i]=rig[chg[k]^1][i]=mx[chg[k]^1][i]=0;
lef[chg[k]][i|1]=rig[chg[k]][i|1]=mx[chg[k]][i|1]=r-mid;
lef[chg[k]^1][i|1]=rig[chg[k]^1][i|1]=mx[chg[k]^1][i|1]=0;
chg[k]=-1;
}return;
}
void cchg(int k,int l,int r,int le,int ri,int v)
{
pushdown(k,l,r);
if(le<=l&&r<=ri){
sm[k]=v?r-l+1:0;
lef[v][k]=rig[v][k]=mx[v][k]=r-l+1;
lef[v^1][k]=rig[v^1][k]=mx[v^1][k]=0;
chg[k]=v;
return;
}int i=k<<1,mid=l+r>>1;
if(le<=mid) cchg(i,l,mid,le,ri,v);
if(mid<ri) cchg(i|1,mid+1,r,le,ri,v);
pushup(k,l,r);
return;
}
void ctag(int k,int l,int r,int le,int ri)
{
pushdown(k,l,r);
if(le<=l&&r<=ri){
tag[k]=1;
sm[k]=r-l+1-sm[k];
swap(lef[0][k],lef[1][k]);
swap(rig[0][k],rig[1][k]);
swap(mx[0][k],mx[1][k]);
return;
}int i=k<<1,mid=l+r>>1;
if(le<=mid) ctag(i,l,mid,le,ri);
if(mid<ri) ctag(i|1,mid+1,r,le,ri);
pushup(k,l,r);
return;
}
int cask1(int k,int l,int r,int le,int ri)
{
pushdown(k,l,r);pushup(k,l,r);
if(le<=l&&r<=ri) return sm[k];
int i=k<<1,mid=l+r>>1,sum=0;
if(le<=mid) sum+=cask1(i,l,mid,le,ri);
if(mid<ri) sum+=cask1(i|1,mid+1,r,le,ri);
return sum;
}
int cask2(int k,int l,int r,int le,int ri)
{
pushdown(k,l,r);pushup(k,l,r);
if(le<=l&&r<=ri) return mx[1][k];
int i=k<<1,mid=l+r>>1,mxx=0;
if(le<=mid&&mid<ri) mxx=max(max(cask2(i,l,mid,le,ri),cask2(i|1,mid+1,r,le,ri)),min(mid-le+1,rig[1][i])+min(ri-mid,lef[1][i|1]));
else if(le<=mid) mxx=cask2(i,l,mid,le,ri);
else if(mid<ri) mxx=cask2(i|1,mid+1,r,le,ri);
return mxx;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i) a[i]=read();
build(1,1,n);
while(m--){
int p=read(),l=read()+1,r=read()+1;
if(p==0) cchg(1,1,n,l,r,0);
else if(p==1) cchg(1,1,n,l,r,1);
else if(p==2) ctag(1,1,n,l,r);
else if(p==3) printf("%d
",cask1(1,1,n,l,r));
else printf("%d
",cask2(1,1,n,l,r));
}return 0;
}
以上是关于[SCOI2010]序列操作的主要内容,如果未能解决你的问题,请参考以下文章