[SCOI2010]序列操作[分块or线段树]
Posted 神犇(shenben)
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[SCOI2010]序列操作[分块or线段树]相关的知识,希望对你有一定的参考价值。

#include<cstdio> #include<iostream> #define lc k<<1 #define rc k<<1|1 using namespace std; const int N=1e5+5; int n,m,a[N]; struct sgt{ int sum,tag,rev,max1,max0,lss0,rss0,lss1,rss1,lp,rp,l,r; }s,tr[N<<2]; inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<\'0\'||ch>\'9\'){if(ch==\'-\')f=-1;ch=getchar();} while(ch>=\'0\'&&ch<=\'9\'){x=x*10+ch-\'0\';ch=getchar();} return x*f; } sgt merge(sgt left,sgt right){ sgt now; now.lp=left.lp; now.rp=right.rp; now.sum=left.sum+right.sum; now.lss0=left.lss0; now.rss0=right.rss0; if(!right.lp&&!left.sum) now.lss0=max(now.lss0,left.r-left.l+1+right.lss0); if(!left.rp&&!right.sum) now.rss0=max(now.rss0,right.r-right.l+1+left.rss0); now.max0=max(left.max0,right.max0); if(!left.rp&&!right.lp) now.max0=max(now.max0,left.rss0+right.lss0); now.lss1=left.lss1; now.rss1=right.rss1; if(right.lp&&left.sum==left.r-left.l+1) now.lss1=max(now.lss1,left.sum+right.lss1); if(left.rp&&right.sum==right.r-right.l+1) now.rss1=max(now.rss1,right.sum+left.rss1); now.max1=max(left.max1,right.max1); if(left.rp&&right.lp) now.max1=max(now.max1,left.rss1+right.lss1); return now; } void updata(int k){ tr[k].lp=tr[lc].lp; tr[k].rp=tr[rc].rp; tr[k].sum=tr[lc].sum+tr[rc].sum; tr[k].lss0=tr[lc].lss0; tr[k].rss0=tr[rc].rss0; if(!tr[rc].lp&&!tr[lc].sum) tr[k].lss0=max(tr[k].lss0,tr[lc].r-tr[lc].l+1+tr[rc].lss0); if(!tr[lc].rp&&!tr[rc].sum) tr[k].rss0=max(tr[k].rss0,tr[rc].r-tr[rc].l+1+tr[lc].rss0); tr[k].max0=max(tr[lc].max0,tr[rc].max0); if(!tr[lc].rp&&!tr[rc].lp) tr[k].max0=max(tr[k].max0,tr[lc].rss0+tr[rc].lss0); tr[k].lss1=tr[lc].lss1; tr[k].rss1=tr[rc].rss1; if(tr[rc].lp&&tr[lc].sum==tr[lc].r-tr[lc].l+1) tr[k].lss1=max(tr[k].lss1,tr[lc].sum+tr[rc].lss1); if(tr[lc].rp&&tr[rc].sum==tr[rc].r-tr[rc].l+1) tr[k].rss1=max(tr[k].rss1,tr[rc].sum+tr[lc].rss1); tr[k].max1=max(tr[lc].max1,tr[rc].max1); if(tr[lc].rp&&tr[rc].lp) tr[k].max1=max(tr[k].max1,tr[lc].rss1+tr[rc].lss1); } void pushdown(int k){ if(~tr[k].tag){ // tr[k].rev=0; if(tr[k].tag){ tr[lc].lp=tr[lc].rp=1; tr[lc].lss1=tr[lc].rss1=tr[lc].max1=tr[lc].sum=tr[lc].r-tr[lc].l+1; tr[lc].lss0=tr[lc].rss0=tr[lc].max0=0; tr[rc].lp=tr[rc].rp=1; tr[rc].lss1=tr[rc].rss1=tr[rc].max1=tr[rc].sum=tr[rc].r-tr[rc].l+1; tr[rc].lss0=tr[rc].rss0=tr[rc].max0=0; } else{ tr[lc].lp=tr[lc].rp=0; tr[lc].lss1=tr[lc].rss1=tr[lc].max1=tr[lc].sum=0; tr[lc].lss0=tr[lc].rss0=tr[lc].max0=tr[lc].r-tr[lc].l+1; tr[rc].lp=tr[rc].rp=0; tr[rc].lss1=tr[rc].rss1=tr[rc].max1=tr[rc].sum=0; tr[rc].lss0=tr[rc].rss0=tr[rc].max0=tr[rc].r-tr[rc].l+1; } tr[lc].tag=tr[rc].tag=tr[k].tag;tr[k].tag=-1; // return ; } if(tr[k].rev){ tr[k].rev=0;tr[lc].rev=1;tr[rc].rev=1; tr[lc].sum=tr[lc].r-tr[lc].l+1-tr[lc].sum; tr[lc].lp^=1;tr[lc].rp^=1; swap(tr[lc].max0,tr[lc].max1); swap(tr[lc].lss0,tr[lc].lss1); swap(tr[lc].rss0,tr[lc].rss1); tr[rc].sum=tr[rc].r-tr[rc].l+1-tr[rc].sum; tr[rc].lp^=1;tr[rc].rp^=1; swap(tr[rc].max0,tr[rc].max1); swap(tr[rc].lss0,tr[rc].lss1); swap(tr[rc].rss0,tr[rc].rss1); } } void deal(int k,int v){ if(v){ tr[k].lp=tr[k].rp=1; tr[k].sum=tr[k].max1=tr[k].lss1=tr[k].rss1=tr[k].r-tr[k].l+1; tr[k].max0=tr[k].lss0=tr[k].rss0=0; } else{ tr[k].lp=tr[k].rp=0; tr[k].max0=tr[k].lss0=tr[k].rss0=tr[k].r-tr[k].l+1; tr[k].sum=tr[k].max1=tr[k].lss1=tr[k].rss1=0; } } void vpt(int k){ if(tr[k].l==tr[k].r) return ; pushdown(k); vpt(lc); vpt(rc); } void build(int k,int l,int r){ tr[k].l=l;tr[k].r=r;tr[k].tag=-1; if(l==r){ tr[k].lp=tr[k].rp=a[l]; tr[k].sum=tr[k].max1=tr[k].lss1=tr[k].rss1=(a[l]==1); tr[k].max0=tr[k].lss0=tr[k].rss0=(a[l]==0); return ; } int mid=l+r>>1; build(lc,l,mid); build(rc,mid+1,r); updata(k); } void cover(int k,int x,int y,int v){ int l=tr[k].l,r=tr[k].r; if(l==x&&r==y){ vpt(k); deal(k,v); if(l!=r) tr[k].tag=v; return ; } pushdown(k); int mid=l+r>>1; if(y<=mid) cover(lc,x,y,v); else if(x>mid) cover(rc,x,y,v); else cover(lc,x,mid,v),cover(rc,mid+1,y,v); updata(k); } void rever(int k,int x,int y){ int l=tr[k].l,r=tr[k].r; if(l==x&&r==y){ vpt(k); tr[k].sum=tr[k].r-tr[k].l+1-tr[k].sum; tr[k].lp^=1;tr[k].rp^=1; swap(tr[k].max0,tr[k].max1); swap(tr[k].lss0,tr[k].lss1); swap(tr[k].rss0,tr[k].rss1); if(l!=r) tr[k].rev=1; return ; } pushdown(k); int mid=l+r>>1; if(y<=mid) rever(lc,x,y); else if(x>mid) rever(rc,x,y); else rever(lc,x,mid),rever(rc,mid+1,y); updata(k); } int query_sum(int k,int x,int y){ int l=tr[k].l,r=tr[k].r; if(l==x&&r==y) return tr[k].sum; pushdown(k); int mid=l+r>>1; if(y<=mid) return query_sum(lc,x,y); else if(x>mid) return query_sum(rc,x,y); else return query_sum(lc,x,mid)+ query_sum(rc,mid+1,y); } sgt query_max(int k,int x,int y){ int l=tr[k].l,r=tr[k].r; if(l==x&&r==y) return tr[k]; pushdown(k); int mid=l+r>>1; if(y<=mid) return query_max(lc,x,y); else if(x>mid) return query_max(rc,x,y); else{ sgt k1=query_max(lc,x,mid); sgt k2=query_max(rc,mid+1,y); return merge(k1,k2); } } int main(){ freopen("operation.in","r",stdin); freopen("operation.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,opt,x,y;i<=m;i++){ opt=read();x=read()+1;y=read()+1; if(opt<2) cover(1,x,y,opt); else if(opt==2) rever(1,x,y); else if(opt==3) printf("%d\\n",query_sum(1,x,y)); else{ s=query_max(1,x,y); printf("%d\\n",s.max1); } } return 0; }

#include<cstdio> #include<iostream> using namespace std; inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<\'0\'||ch>\'9\'){if(ch==\'-\')f=-1;ch=getchar();} while(ch>=\'0\'&&ch<=\'9\'){x=x*10+ch-\'0\';ch=getchar();} return x*f; } const int N=1000100; int n,m,a[N]; int sum(int l,int r){ int res=0; for(int i=l;i<=r;i++) res+=a[i]; return res; } int conti(int l,int r){ int res=0; for(int i=l,j=i;i<=r;){ if(a[i]){ for(j=i+1;j<=r;j++){ if(!a[j]) break; } res=max(res,j-i); i=j+1; } else i++; } return res; } void out(){ for(int j=0;j<n;j++) printf("%d ",a[j]);printf("\\n\\n\\n"); } int main(){ n=read();m=read(); for(int i=0;i<n;i++) a[i]=read(); for(int i=0,opt,x,y;i<m;i++){ opt=read();x=read();y=read(); if(opt==0){ for(int j=x;j<=y;j++) a[j]=0; } if(opt==1){ for(int j=x;j<=y;j++) a[j]=1; } if(opt==2){ for(int j=x;j<=y;j++) a[j]^=1; } if(opt==3){ printf("%d\\n",sum(x,y)); } if(opt==4){ printf("%d\\n",conti(x,y)); } } return 0; }
/* 本题的难度在于标记的下放。 下面说一下我的做法: 1.覆盖标记:直接打上就好了 2.取反标记: <1>如果有tag标记,将tag标记取反,退出. <2>如果有rev标记,直接退出 <3>无标记,打上rev标记,退出 维护: sum(当前区间和),lss1(区间从左端点连续1的长度),rss1(区间从右端点连续1的长度),sc1(区间连续1的长度) lss0,rss0,sc0同理。tag(覆盖标记和取反标记整一起了) */ #include<cmath> #include<cstdio> #include<cstring> #include<iostream> using namespace std; const int N=1e5+5; const int M=505; int a[N],bl[N],n,m,size; int tag[M],lss0[M],rss0[M],sc0[M],lss1[M],rss1[M],sc1[M],sum[M]; void init(int i){ tag[i]=-1;lss0[i]=rss0[i]=sc0[i]=lss1[i]=rss1[i]=sc1[i]=sum[i]=0; for(int j=(i-1)*size+1;j<=min(n,i*size);j++) if(a[j]) sum[i]++; int fl=0,p=0; for(int j=(i-1)*size+1;j<=min(n,i*size);j++){ if(!a[j]&&!fl) lss0[i]++; else fl=1; if(!a[j]) p++;else p=0; sc0[i]=max(sc0[i],p); } fl=0; for(int j=min(n,i*size);j>(i-1)*size;j--){ if(!a[j]&&!fl) rss0[i]++; else fl=1; } fl=0,p=0; for(int j=(i-1)*size+1;j<=min(n,i*size);j++){ if(a[j]&&!fl) lss1[i]++; else fl=1; if(a[j]) p++;else p=0; sc1[i]=max(sc1[i],p); } fl=0; for(int j=min(n,i*size);j>(i-1)*size;j--){ if(a[j]&&!fl) rss1[i]++; else fl=1; } } void pushdown(int i){ if(tag[i]==-1) return; if(tag[i]==0||tag[i]==1) for(int j=(i-1)*size+1;j<=i*size;j++) a[j]=tag[i]; else for(int j=(i-1)*size+1;j<=i*size;j++) a[j]^=1; tag[i]=-1; } void cover(int x,int y,int v){ pushdown(bl[x]); for(int i=x;i<=min(y,bl[x]*size);i++) a[i]=v; init(bl[x]); for(int i=bl[x]+1;i<bl[y];i++){ tag[i]=v; if(v) lss1[i]=rss1[i]=sc1[i]=sum[i]=size,lss0[i]=rss0[i]=sc0[i]=0; else lss1[i]=rss1[i]=sc1[i]=sum[i]=0,lss0[i]=rss0[i]=sc0[i]=size; } if(bl[x]==bl[y]) return; pushdown(bl[y]); for(int i=(bl[y]-1)*size+1;i<=y;i++) a[i]=v; init(bl[y]); } void rever(int x,int y){ pushdown(bl[x]); for(int i=x;i<=min(y,bl[x]*size);i++) a[i]^=1; init(bl[x]); for(int i=bl[x]+1;i<bl[y];i++){ if(tag[i]==-1) tag[i]=2; else if(tag[i]==0) tag[i]=1; else if(tag[i]==1) tag[i]=0; else tag[i]=-1; swap(lss0[i],lss1[i]);swap(rss0[i],rss1[i]); swap(sc0[i],sc1[i]);sum[i]=size-sum[i]; } if(bl[x]==bl[y]) return; pushdown(bl[y]); for(int i=(bl[y]-1)*size+1;i<=y;i++) a[i]^=1; init(bl[y]); } int query_sum(int x,int y){ int ans=0; pushdown(bl[x]); for(int i=x;i<=min(y,bl[x]*size);i++) if(a[i]) ans++; for(int i=bl[x]+1;i<bl[y];i++) ans+=sum[i]; if(bl[x]==bl[y]) return ans; pushdown(bl[y]); for(int i=(bl[y]-1)*size+1;i<=y;i++) if(a[i]) ans++; return ans; } int query_num(int x,int y){ int ans=0,l=0; pushdown(bl[x]); for(int i=x;i<=min(y,bl[x]*size);i++){ if(a[i]) l++;else l=0; ans=max(ans,l); } for(int i=bl[x]+1;i<bl[y];i++){ l+=lss1[i]; ans=max(ans,l); ans=max(ans,sc1[i]); if(lss1[i]!=size) l=rss1[i]; } if(bl[x]==bl[y]) return max(ans,l); pushdown(bl[y]); for(int i=(bl[y]-1)*size+1;i<=y;i++){ if(a[i]) l++;else l=0; ans=max(ans,l); } return ans; } int main(){ memset(tag,-1,sizeof(tag)); scanf("%d%d",&n,&m); size=sqrt(n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); bl[i]=(i-1)/size+1; } for(int i=1;i<=bl[n];i++) init(i); for(int i=1,op,x,y;i<=m;i++){ scanf("%d%d%d",&op,&x,&y);x++;y++; if(op==0) cover(x,y,0); if(op==1) cover(x,y,1); if(op==2) rever(x,y); if(op==3) printf("%d\\n",query_sum(x,y)); if(op==4) printf("%d\\n",query_num(x,y)); } return 0; }
以上是关于[SCOI2010]序列操作[分块or线段树]的主要内容,如果未能解决你的问题,请参考以下文章