【传送门:BZOJ1858】
简要题意:
给出一个长度为n的01序列,有五种操作,m个操作:
0 x y将第x个数到第y个数都变成0
1 x y将第x个数到第y个数都变成1
2 x y将第x个数到第y个数的所有数取反(即0变为1,1变为0)
3 x y求出第x个数到第y个数有多少个1
4 x y求出第x个数到第y个数最多有多少个连续的1
题解:
线段树麻烦题
对于一段区间,我们维护这些东西:
c表示有多少个1,c0表示最多有多少个连续的0,c1表示最多有多少个连续的1
lc0表示从左端点开始向右有多少个连续的0,lc1表示从左端点开始向右有多少个连续的1
rc0表示从右端点开始向左有多少个连续的0,rc1表示从右端点开始向左有多少个连续的1
然后对于标记,lazy01表示当前区间的子区间变0或变1或不变,fan表示当前区间是否需要取反
因为不能知道先后顺序,所以我们使得这两个标记在一个区间内不同时存在就好了
假如当前区间原本就有取反标记,如果我要使得这个区间变为0或1,那么就要把取反标记去掉(因为这个时候取反没有用的,反正也会变成0或1)
假如当前区间原本就有01标记,如果我要使得这个区间取反,那么就要把取反标记去掉,然后把01标记变成另一个01标记(也就是原本要变0的就变1,原本要变1的就变0,就是相当于取反了)
然后其他的无脑做就好了,第四个操作略微有些麻烦
参考代码:
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; struct node { int l,r,lc,rc,c,c0,c1; int lc0,lc1,rc0,rc1; int lazy01,fan; }tr[210000];int trlen; void bt(int l,int r) { int now=++trlen; tr[now].l=l;tr[now].r=r; tr[now].c=tr[now].c0=tr[now].c1=tr[now].lc0=tr[now].lc1=tr[now].rc0=tr[now].rc1=0; tr[now].lazy01=-1;tr[now].fan=0; tr[now].lc=tr[now].rc=-1; if(l<r) { int mid=(l+r)/2; tr[now].lc=trlen+1;bt(l,mid); tr[now].rc=trlen+1;bt(mid+1,r); } } void follow(int now) { int lc=tr[now].lc,rc=tr[now].rc; tr[now].c=tr[lc].c+tr[rc].c; tr[now].c0=max(tr[lc].rc0+tr[rc].lc0,max(tr[lc].c0,tr[rc].c0)); tr[now].c1=max(tr[lc].rc1+tr[rc].lc1,max(tr[lc].c1,tr[rc].c1)); if(tr[lc].lc0==(tr[lc].r-tr[lc].l+1)&&tr[rc].rc0==(tr[rc].r-tr[rc].l+1)) tr[now].lc0=tr[now].rc0=tr[now].r-tr[now].l+1; else if(tr[lc].lc0==(tr[lc].r-tr[lc].l+1)&&tr[rc].rc0!=(tr[rc].r-tr[rc].l+1)) tr[now].lc0=tr[lc].lc0+tr[rc].lc0,tr[now].rc0=tr[rc].rc0; else if(tr[lc].lc0!=(tr[lc].r-tr[lc].l+1)&&tr[rc].rc0==(tr[rc].r-tr[rc].l+1)) tr[now].rc0=tr[lc].rc0+tr[rc].rc0,tr[now].lc0=tr[lc].lc0; else tr[now].lc0=tr[lc].lc0,tr[now].rc0=tr[rc].rc0; if(tr[lc].lc1==(tr[lc].r-tr[lc].l+1)&&tr[rc].rc1==(tr[rc].r-tr[rc].l+1)) tr[now].lc1=tr[now].rc1=tr[now].r-tr[now].l+1; else if(tr[lc].lc1==(tr[lc].r-tr[lc].l+1)&&tr[rc].rc1!=(tr[rc].r-tr[rc].l+1)) tr[now].lc1=tr[lc].lc1+tr[rc].lc1,tr[now].rc1=tr[rc].rc1; else if(tr[lc].lc1!=(tr[lc].r-tr[lc].l+1)&&tr[rc].rc1==(tr[rc].r-tr[rc].l+1)) tr[now].rc1=tr[lc].rc1+tr[rc].rc1,tr[now].lc1=tr[lc].lc1; else tr[now].lc1=tr[lc].lc1,tr[now].rc1=tr[rc].rc1; } void update01(int now) { int lc=tr[now].lc,rc=tr[now].rc; if(lc!=-1) { if(tr[now].lazy01==0) { tr[lc].c=tr[lc].c1=0; tr[lc].c0=tr[lc].r-tr[lc].l+1; tr[lc].lc0=tr[lc].rc0=tr[lc].r-tr[lc].l+1; tr[lc].lc1=tr[lc].rc1=0; tr[lc].lazy01=0; } else { tr[lc].c=tr[lc].c1=tr[lc].r-tr[lc].l+1; tr[lc].c0=0; tr[lc].lc0=tr[lc].rc0=0; tr[lc].lc1=tr[lc].rc1=tr[lc].r-tr[lc].l+1; tr[lc].lazy01=1; } if(tr[lc].fan==1) tr[lc].fan=0; } if(rc!=-1) { if(tr[now].lazy01==0) { tr[rc].c=tr[rc].c1=0; tr[rc].c0=tr[rc].r-tr[rc].l+1; tr[rc].lc0=tr[rc].rc0=tr[rc].r-tr[rc].l+1; tr[rc].lc1=tr[rc].rc1=0; tr[rc].lazy01=0; } else { tr[rc].c=tr[rc].c1=tr[rc].r-tr[rc].l+1; tr[rc].c0=0; tr[rc].lc0=tr[rc].rc0=0; tr[rc].lc1=tr[rc].rc1=tr[rc].r-tr[rc].l+1; tr[rc].lazy01=1; } if(tr[rc].fan==1) tr[rc].fan=0; } tr[now].lazy01=-1; } void updatef(int now) { int lc=tr[now].lc,rc=tr[now].rc; if(lc!=-1) { tr[lc].c=(tr[lc].r-tr[lc].l+1)-tr[lc].c; swap(tr[lc].c0,tr[lc].c1); swap(tr[lc].lc0,tr[lc].lc1); swap(tr[lc].rc0,tr[lc].rc1); tr[lc].fan^=1; if(tr[lc].fan==1&&tr[lc].lazy01!=-1) { tr[lc].lazy01^=1; tr[lc].fan=0; } } if(rc!=-1) { tr[rc].c=(tr[rc].r-tr[rc].l+1)-tr[rc].c; swap(tr[rc].c0,tr[rc].c1); swap(tr[rc].lc0,tr[rc].lc1); swap(tr[rc].rc0,tr[rc].rc1); tr[rc].fan^=1; if(tr[rc].fan==1&&tr[rc].lazy01!=-1) { tr[rc].lazy01^=1; tr[rc].fan=0; } } tr[now].fan=0; } void change(int now,int l,int r,int c) { if(tr[now].l==l&&tr[now].r==r) { if(c==0) { tr[now].c=tr[now].c1=0; tr[now].c0=r-l+1; tr[now].lc0=tr[now].rc0=r-l+1; tr[now].lc1=tr[now].rc1=0; tr[now].lazy01=0; } else { tr[now].c=tr[now].c1=r-l+1; tr[now].c0=0; tr[now].lc0=tr[now].rc0=0; tr[now].lc1=tr[now].rc1=r-l+1; tr[now].lazy01=1; } if(tr[now].fan==1) tr[now].fan=0; return ; } int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2; if(tr[now].lazy01!=-1) update01(now); if(tr[now].fan==1) updatef(now); if(r<=mid) change(lc,l,r,c); else if(l>mid) change(rc,l,r,c); else change(lc,l,mid,c),change(rc,mid+1,r,c); follow(now); } void qufan(int now,int l,int r) { if(tr[now].l==l&&tr[now].r==r) { tr[now].c=(r-l+1)-tr[now].c; swap(tr[now].c0,tr[now].c1); swap(tr[now].lc0,tr[now].lc1); swap(tr[now].rc0,tr[now].rc1); tr[now].fan^=1; if(tr[now].fan==1&&tr[now].lazy01!=-1) { tr[now].lazy01^=1; tr[now].fan=0; } return ; } int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2; if(tr[now].lazy01!=-1) update01(now); if(tr[now].fan==1) updatef(now); if(r<=mid) qufan(lc,l,r); else if(l>mid) qufan(rc,l,r); else qufan(lc,l,mid),qufan(rc,mid+1,r); follow(now); } int findc(int now,int l,int r) { if(tr[now].l==l&&tr[now].r==r) return tr[now].c; int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2; if(tr[now].lazy01!=-1) update01(now); if(tr[now].fan==true) updatef(now); if(r<=mid) return findc(lc,l,r); else if(l>mid) return findc(rc,l,r); else return findc(lc,l,mid)+findc(rc,mid+1,r); } int tot,p[110000]; void findd(int now,int l,int r) { if(tr[now].l==l&&tr[now].r==r) { p[++tot]=now; return ; } int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2; if(tr[now].lazy01!=-1) update01(now); if(tr[now].fan==true) updatef(now); if(r<=mid) findd(lc,l,r); else if(l>mid) findd(rc,l,r); else findd(lc,l,mid),findd(rc,mid+1,r); } int a[110000]; int main() { freopen("operation.in","r",stdin); freopen("operation.out","w",stdout); int n,m; scanf("%d%d",&n,&m); trlen=0;bt(1,n); for(int i=1;i<=n;i++) { int c; scanf("%d",&c); change(1,i,i,c); } for(int i=1;i<=m;i++) { int opt,x,y; scanf("%d%d%d",&opt,&x,&y);x++;y++; if(opt==0) change(1,x,y,0); if(opt==1) change(1,x,y,1); if(opt==2) qufan(1,x,y); if(opt==3) printf("%d ",findc(1,x,y)); if(opt==4) { tot=0; findd(1,x,y); int ans=0,t=0; for(int i=1;i<=tot;i++) { ans=max(ans,tr[p[i]].c1); if(tr[p[i]].c1==(tr[p[i]].r-tr[p[i]].l+1)) t+=tr[p[i]].c1; else { ans=max(ans,t+tr[p[i]].lc1); t=tr[p[i]].rc1; } ans=max(ans,t); } printf("%d ",ans); } } return 0; }