【題解】[Scoi2010]序列操作
阿新 • • 發佈:2020-12-24
Statement
給定一個長為 \(n\) 的 01
序列,要求實現 \(5\) 種操作:
0 a b
將 \([a,b]\) 全部設為 \(0\) .1 a b
將 \([a,b]\) 全部設為 \(1\) .2 a b
將區間所有數取反 。3 a b
詢問區間內 \(1\) 的個數。4 a b
詢問區間內連續 \(1\) 的個數。
Solution
頂風作案寫DS.jpg
線段樹噁心題,但是很經典,碼得也算能看,就拿出來當板子了。
維護字首 \(0/1\) 、字尾 \(0/1\) 、連續 \(0/1\) 的個數,和區間中 \(0/1\) 的個數。注意覆蓋標記優先順序高於翻轉標記。
線段樹噁心題,碼就完了。實在不行,重構就是了
好在碼得並不慢,調得也很快,調過樣例之後一遍就過拍了(本地資料手動 diff
)。
你谷開 O2 跑進了第二頁,BZOJ 沒開 O2 卡在第一頁底端/youl
希望下次寫結構體函式的時候:
\(\huge 真的不要再忘記return了\)
Code
//Author: RingweEH //菜雞REH頂風作案 const int N=1e5+10; int n,q,a[N]; struct SegmentTree { struct Node { int cntw,cntb,lcntw,rcntw,lcntb,rcntb,mxw,mxb; //w個數,b個數,左/右數w個數,左/右數b個數,連續w/b最大值 Node( int _cntw=0,int _cntb=0,int _lcntw=0,int _lcntb=0, int _rcntw=0,int _rcntb=0,int _mxw=0,int _mxb=0 ) { cntw=_cntw; cntb=_cntb; lcntw=_lcntw; lcntb=_lcntb; rcntb=_rcntb; rcntw=_rcntw; mxw=_mxw; mxb=_mxb; } Node operator + ( const Node &tmp ) const { Node res; res.cntw=cntw+tmp.cntw; res.cntb=cntb+tmp.cntb; res.lcntw=cntb ? lcntw : cntw+tmp.lcntw; res.lcntb=cntw ? lcntb : cntb+tmp.lcntb; res.rcntw=tmp.cntb ? tmp.rcntw : tmp.cntw+rcntw; res.rcntb=tmp.cntw ? tmp.rcntb : tmp.cntb+rcntb; res.mxw=max( max(mxw,tmp.mxw),rcntw+tmp.lcntw ); res.mxb=max( max(mxb,tmp.mxb),rcntb+tmp.lcntb ); return res; } }tr[N<<2]; int len[N<<2],tag1[N<<2],tag2[N<<2]; //區間長度,區間賦值標記(-1/0/1),區間取反(0/1) void Operate( int pos,int opt ) { Node &te=tr[pos]; if ( opt==0 ) //reset( 0 ) { tag2[pos]=tag1[pos]=0; int t=len[pos]; te=Node( 0,t,0,t,0,t,0,t ); } if ( opt==1 ) //reset( 1 ) { tag2[pos]=0,tag1[pos]=1; int t=len[pos]; te=Node( t,0,t,0,t,0,t,0 ); } if ( opt==2 ) //flip { tag2[pos]^=1; swap( te.cntw,te.cntb ); swap( te.mxb,te.mxw ); swap( te.lcntw,te.lcntb ); swap( te.rcntw,te.rcntb ); } } void Pushdown( int pos ) { if ( tag1[pos]>-1 ) Operate( pos<<1,tag1[pos] ),Operate( pos<<1|1,tag1[pos] ); if ( tag2[pos] ) Operate( pos<<1,2 ),Operate( pos<<1|1,2 ); tag1[pos]=-1; tag2[pos]=0; } void Modify( int pos,int L,int R,int l,int r,int val ) { if ( r<L || R<l ) return; if ( l<=L && R<=r ) { Operate( pos,val ); return; } Pushdown( pos ); int mid=(L+R)>>1; Modify( pos<<1,L,mid,l,r,val ); Modify( pos<<1|1,mid+1,R,l,r,val ); tr[pos]=tr[pos<<1]+tr[pos<<1|1]; } Node Query( int pos,int L,int R,int l,int r ) { if ( r<L || R<l ) return Node(); if ( l<=L && R<=r ) return tr[pos]; Pushdown( pos ); int mid=(L+R)>>1; Node lc=Query(pos<<1,L,mid,l,r),rc=Query(pos<<1|1,mid+1,R,l,r); return lc+rc; } void Build( int pos,int L,int R ) { len[pos]=R-L+1; tag1[pos]=-1; if ( L==R ) { int t=a[L]; tr[pos]=Node(t,t^1,t,t^1,t,t^1,t,t^1 ); return; } int mid=(L+R)>>1; Build( pos<<1,L,mid ); Build( pos<<1|1,mid+1,R ); tr[pos]=tr[pos<<1]+tr[pos<<1|1]; } int Answer( int l,int r,int opt ) { Node res=Query( 1,1,n,l,r ); if ( opt==3 ) return res.cntw; else return res.mxw; } //w,b,lw,lb,rw,rb,mw,mb; }Tr; int main() { n=read(); q=read(); for ( int i=1; i<=n; i++ ) a[i]=read(); Tr.Build(1,1,n); while ( q-- ) { int opt=read(),l=read()+1,r=read()+1; if ( opt<3 ) Tr.Modify( 1,1,n,l,r,opt ); else printf( "%d\n",Tr.Answer(l,r,opt) ); } return 0; }