SCOI 2010 序列操作
题目描述
lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作:
0 a b 把[a, b]区间内的所有数全变成0
1 a b 把[a, b]区间内的所有数全变成1
2 a b 把[a,b]区间内的所有数全部取反,也就是说把所有的0变成1,把所有的1变成0
3 a b 询问[a, b]区间内总共有多少个1
4 a b 询问[a, b]区间内最多有多少个连续的1
对于每一种询问操作,lxhgww都需要给出回答,聪明的程序员们,你们能帮助他吗?
一道坑爹的线段树,我们维护7个信息,区间左右段点值,左右端点的连续长度,区间内的最长0串和1串。注意标记合并,翻转标记是xor更新的。覆盖标记遇上翻转标记是改覆盖标记类型。或者覆盖。
#include<bits/stdc++.h> #define sight(x) ('0'<=x&&x<='9') #define MID ((l+r)>>1) #define max(x,y) (x)>(y)?(x):(y) #define node No #define o(x) (x=(x&1)+1) #define L(x) ((x)<<1) #define R(x) ((x)<<1|1) #define La lazy #define N 400007 using namespace std; inline void read(int &x) { static char c; static int b; for (b=1,c=getchar();!sight(c);c=getchar()) if (c=='-') b=-1; for (x=0;sight(c);c=getchar()) x=x*10+c-48; x*=b; } struct Node{ int sum,l,r,llen,rlen,ma[2],siz; inline void add(Node x,Node y){ sum=x.sum+y.sum; siz=x.siz+y.siz; l=x.l; r=y.r; ma[0]=max(x.ma[0],y.ma[0]); ma[1]=max(x.ma[1],y.ma[1]); if (x.r==y.l) ma[x.r]=max(ma[x.r],x.rlen+y.llen); llen=x.llen; rlen=y.rlen; if (x.llen==x.siz) llen=x.llen+((y.l==x.r)?y.llen:0); if (y.rlen==y.siz) rlen=y.rlen+((y.l==x.r)?x.rlen:0); } inline void G1() { sum=siz-sum; l^=1,r^=1; swap(ma[0],ma[1]); } inline void L1(int x) { sum=x?siz:0; l=r=x; ma[x]=siz; ma[x^1]=0; llen=rlen=siz; } }T[N],RR; int La[N],La1[N]; inline void updata(int node){ if (La[No]) { La[L(No)]=La[R(No)]=La[No]; T[L(No)].L1(La[No]&1); La1[L(No)]=0; T[R(No)].L1(La[No]&1); La1[R(No)]=0; La[No]=0; return;} if (La1[No]) { if (La[L(No)]) o(La[L(No)]),La1[L(No)]=0; else La1[L(No)]^=1; if (La[R(No)]) o(La[R(No)]),La1[R(No)]=0; else La1[R(No)]^=1; La1[No]=0; T[L(No)].G1(); T[R(No)].G1(); return;} } void build(int node,int l,int r){ if (l==r) { read(T[node].sum); T[node].l=T[node].r=T[node].sum; T[node].llen=T[node].rlen=T[node].siz=1; T[node].ma[T[node].sum]=1; return; } build(L(No),l,MID); build(R(No),MID+1,r); T[node].add(T[L(No)],T[R(No)]); } void change(int node,int l,int r,int L,int R,int col){ if (L<=l&&r<=R) { int XX=col&3; if (XX) { La1[No]=0; La[No]=XX; T[No].L1(XX&1);} else { if (La[No]) o(La[No]),La1[No]=0; else La1[No]^=1; T[No].G1(); } return; } if (La[node]||La1[node]) updata(node); if (R<=MID) change(L(No),l,MID,L,R,col); else if (L> MID) change(R(No),MID+1,r,L,R,col); else change(L(No),l,MID,L,MID,col),change(R(No),MID+1,r,MID+1,R,col); T[No].add(T[L(No)],T[R(No)]); } Node query(int node,int l,int r,int L,int R){ if (L<=l&&r<=R) return T[node]; if (La[node]||La1[node]) updata(node); if (R<=MID) return query(L(No),l,MID,L,R); if (L> MID) return query(R(No),MID+1,r,L,R); Node XX; XX.add(query(L(No),l,MID,L,MID),query(R(No),MID+1,r,MID+1,R)); return XX; } void write(int x){ if (x<10) {putchar('0'+x);return;}write(x/10); putchar('0'+x%10); } int n,m,op,X,Y; int main () { freopen("a.in","r",stdin); read(n); read(m); build(1,1,n); while(m--) { read(op); read(X); read(Y); X++; Y++; switch (op){ case 0:change(1,1,n,X,Y,2); break; case 1:change(1,1,n,X,Y,1); break; case 2:change(1,1,n,X,Y,4); break; case 3:RR=query(1,1,n,X,Y);write(RR.sum);putchar('\n'); break; case 4:RR=query(1,1,n,X,Y);write(RR.ma[1]);putchar('\n'); break; } } return 0; }