BZOJ_1858_[Scoi2010]序列操作_線段樹
阿新 • • 發佈:2018-03-30
個數 brush build 接下來 inpu content con 線段 void
0 0 0 1 1 0 1 0 1 1
1 0 2
3 0 5
2 2 2
4 0 4
0 3 6
2 3 7
4 2 8
1 0 5
0 5 6
3 3 9
2
6
5
BZOJ_1858_[Scoi2010]序列操作_線段樹
Description
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都需要給出回答,聰明的程序員們,你們能幫助他嗎?
Input
輸入數據第一行包括2個數,n和m,分別表示序列的長度和操作數目 第二行包括n個數,表示序列的初始狀態 接下來m行,每行3個數,op, a, b,(0 < = op < = 4,0 < = a < = b)
Output
對於每一個詢問操作,輸出一行,包括1個數,表示其對應的答案
Sample Input
10 100 0 0 1 1 0 1 0 1 1
1 0 2
3 0 5
2 2 2
4 0 4
0 3 6
2 3 7
4 2 8
1 0 5
0 5 6
3 3 9
Sample Output
52
6
5
HINT
對於30%的數據,1<=n, m<=1000 對於100%的數據,1< = n, m < = 100000
分析:線段樹處理多個標記。
我這裏是先下傳取反標記,後下傳覆蓋標記。
這樣的話。如果操作是先覆蓋後取反,就在取反的函數中判斷一下,如果有覆蓋就把覆蓋的值取反。
代碼:
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define N 100050 #define ls p<<1 #define rs p<<1|1 int t[N<<2],cov[N<<2],rev[N<<2],n,m; int lx[N<<2][2],rx[N<<2][2],nx[N<<2][2],siz[N<<2]; void pushup(int p) { t[p]=t[ls]+t[rs]; for(int i=0;i<2;i++) { if(nx[ls][i]==siz[ls]) lx[p][i]=siz[ls]+lx[rs][i]; else lx[p][i]=lx[ls][i]; if(nx[rs][i]==siz[rs]) rx[p][i]=siz[rs]+rx[ls][i]; else rx[p][i]=rx[rs][i]; nx[p][i]=max(max(rx[ls][i]+lx[rs][i],nx[ls][i]),nx[rs][i]); } } void build(int l,int r,int p) { cov[p]=-1; siz[p]=r-l+1; if(l==r) { scanf("%d",&t[p]); lx[p][1]=rx[p][1]=nx[p][1]=t[p]; lx[p][0]=rx[p][0]=nx[p][0]=!t[p]; return ; } int mid=l+r>>1; build(l,mid,ls); build(mid+1,r,rs); pushup(p); } void pushdown(int p) { if(rev[p]) { t[ls]=siz[ls]-t[ls]; swap(lx[ls][0],lx[ls][1]); swap(rx[ls][0],rx[ls][1]); swap(nx[ls][0],nx[ls][1]); if(cov[ls]!=-1)cov[ls]^=1; rev[ls]^=1; t[rs]=siz[rs]-t[rs]; swap(lx[rs][0],lx[rs][1]); swap(rx[rs][0],rx[rs][1]); swap(nx[rs][0],nx[rs][1]); if(cov[rs]!=-1)cov[rs]^=1; rev[rs]^=1; rev[p]=0; } if(cov[p]!=-1) { int d=cov[p]; cov[ls]=cov[rs]=d; lx[ls][d]=rx[ls][d]=nx[ls][d]=siz[ls]; lx[rs][d]=rx[rs][d]=nx[rs][d]=siz[rs]; lx[ls][!d]=rx[ls][!d]=nx[ls][!d]=lx[rs][!d]=rx[rs][!d]=nx[rs][!d]=0; t[ls]=siz[ls]*d; t[rs]=siz[rs]*d; cov[p]=-1; } } void uprever(int l,int r,int x,int y,int p) { if(x<=l&&y>=r) { t[p]=siz[p]-t[p]; swap(lx[p][0],lx[p][1]); swap(rx[p][0],rx[p][1]); swap(nx[p][0],nx[p][1]); rev[p]^=1; if(cov[p]!=-1) cov[p]^=1; return ; } pushdown(p); int mid=l+r>>1; if(x<=mid) uprever(l,mid,x,y,ls); if(y>mid) uprever(mid+1,r,x,y,rs); pushup(p); } void update(int l,int r,int x,int y,int c,int p) { if(x<=l&&y>=r) { cov[p]=c; lx[p][c]=rx[p][c]=nx[p][c]=siz[p]; lx[p][!c]=rx[p][!c]=nx[p][!c]=0; t[p]=siz[p]*c; return ; } pushdown(p); int mid=l+r>>1; if(x<=mid) update(l,mid,x,y,c,ls); if(y>mid) update(mid+1,r,x,y,c,rs); pushup(p); } int qsum(int l,int r,int x,int y,int p) { if(x<=l&&y>=r) return t[p]; pushdown(p); int re=0,mid=l+r>>1; if(x<=mid) re+=qsum(l,mid,x,y,ls); if(y>mid) re+=qsum(mid+1,r,x,y,rs); return re; } int qcon(int l,int r,int x,int y,int p) { if(x<=l&&y>=r) return nx[p][1]; pushdown(p); int ansl,ansr,ansm,mid=l+r>>1; if(y<=mid) return qcon(l,mid,x,y,ls); else if(x>mid) return qcon(mid+1,r,x,y,rs); else { ansl=qcon(l,mid,x,y,ls); ansr=qcon(mid+1,r,x,y,rs); ansm=min(mid-x+1,rx[ls][1])+min(y-mid,lx[rs][1]); return max(max(ansl,ansr),ansm); } } int main() { scanf("%d%d",&n,&m); int i,opt,x,y; build(1,n,1); for(i=1;i<=m;i++) { scanf("%d%d%d",&opt,&x,&y); x++;y++; if(opt==0) { update(1,n,x,y,0,1); }else if(opt==1) { update(1,n,x,y,1,1); }else if(opt==2) { uprever(1,n,x,y,1); }else if(opt==3) { printf("%d\n",qsum(1,n,x,y,1)); }else { printf("%d\n",qcon(1,n,x,y,1)); } } }
BZOJ_1858_[Scoi2010]序列操作_線段樹