bzoj 1858: [Scoi2010]序列操作
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<n)表示对于区间[a, b]执行标号为op的操作="" <="" div="">
Output
对于每一个询问操作,输出一行,包括1个数,表示其对应的答案
Sample Input
10 10
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
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
Sample Output
5
2
6
5
2
6
5
HINT
对于30%的数据,1<=n, m<=1000
对于100%的数据,1<=n, m<=100000
题解:
其实是蛮简单的一道题(不说了,我交了不下10次。。)
我们需要在维护一些关于0的量,对于2这个操作,其实就是交换0和1的量。。。
#include<stdio.h> #include<iostream> #include<algorithm> #include<string.h> using namespace std; #define p1 (p<<1) #define p2 (p<<1|1) int n,m,i,p,x,y; int a[100005],t[400005],tl[400005]; int tmid[400005],tr[400005],add[400005]; int T[400005],Tmid[400005],Tr[400005],Tl[400005]; int ans[15]; void build(int l,int r,int p) { if(l==r) { add[p]=a[l]; tmid[p]=tl[p]=tr[p]=t[p]=a[l]; Tmid[p]=Tl[p]=Tr[p]=T[p]=1-a[l]; return; } int mid=(l+r)>>1; build(l,mid,p1); build(mid+1,r,p2); t[p]=t[p1]+t[p2]; if(t[p1]==mid-l+1) tl[p]=tl[p1]+tl[p2];else tl[p]=tl[p1]; if(t[p2]==r-mid) tr[p]=tr[p2]+tr[p1];else tr[p]=tr[p2]; tmid[p]=max(tmid[p1],tmid[p2]); tmid[p]=max(tmid[p],tr[p1]+tl[p2]); T[p]=T[p1]+T[p2]; if(T[p1]==mid-l+1) Tl[p]=Tl[p1]+Tl[p2];else Tl[p]=Tl[p1]; if(T[p2]==r-mid) Tr[p]=Tr[p2]+Tr[p1];else Tr[p]=Tr[p2]; Tmid[p]=max(Tmid[p1],Tmid[p2]); Tmid[p]=max(Tmid[p],Tr[p1]+Tl[p2]); } void update(int l,int r,int x,int y,int z,int p) { if(x<=l&&r<=y) { if(z==0) { add[p]=0; T[p]=Tmid[p]=Tr[p]=Tl[p]=r-l+1; t[p]=tmid[p]=tr[p]=tl[p]=0; } else if(z==1) { add[p]=1; T[p]=Tmid[p]=Tr[p]=Tl[p]=0; t[p]=tmid[p]=tr[p]=tl[p]=r-l+1; } else if(z==2) { swap(t[p],T[p]); swap(tl[p],Tl[p]); swap(tr[p],Tr[p]); swap(tmid[p],Tmid[p]); add[p]=1-add[p]; } return; } int mid=(l+r)>>1; if(add[p]!=-1) { update(l,mid,l,mid,add[p],p1); update(mid+1,r,mid+1,r,add[p],p2); add[p]=-1; } if(x<=mid) update(l,mid,x,y,z,p1); if(y>mid) update(mid+1,r,x,y,z,p2); t[p]=t[p1]+t[p2]; if(t[p1]==mid-l+1) tl[p]=tl[p1]+tl[p2];else tl[p]=tl[p1]; if(t[p2]==r-mid) tr[p]=tr[p2]+tr[p1];else tr[p]=tr[p2]; tmid[p]=max(tmid[p1],tmid[p2]); tmid[p]=max(tmid[p],tr[p1]+tl[p2]); T[p]=T[p1]+T[p2]; if(T[p1]==mid-l+1) Tl[p]=Tl[p1]+Tl[p2];else Tl[p]=Tl[p1]; if(T[p2]==r-mid) Tr[p]=Tr[p2]+Tr[p1];else Tr[p]=Tr[p2]; Tmid[p]=max(Tmid[p1],Tmid[p2]); Tmid[p]=max(Tmid[p],Tr[p1]+Tl[p2]); } void solve(int l,int r,int x,int y,int p,int X) { if(x==l&&y==r) { ans[3]=max(ans[3],ans[4]+tl[p]); if(ans[1]==l-X) ans[2]+=tl[p]; if(t[p]==r-l+1) ans[4]+=tr[p];else ans[4]=tr[p]; ans[3]=max(ans[3],tmid[p]); ans[1]+=t[p]; return; } int mid=(l+r)>>1; if(add[p]!=-1) { update(l,mid,l,mid,add[p],p1); update(mid+1,r,mid+1,r,add[p],p2); add[p]=-1; } if(y<=mid) solve(l,mid,x,y,p1,X);else if(x>mid) solve(mid+1,r,x,y,p2,X);else { solve(l,mid,x,mid,p1,X); solve(mid+1,r,mid+1,y,p2,X); } t[p]=t[p1]+t[p2]; if(t[p1]==mid-l+1) tl[p]=tl[p1]+tl[p2];else tl[p]=tl[p1]; if(t[p2]==r-mid) tr[p]=tr[p2]+tr[p1];else tr[p]=tr[p2]; tmid[p]=max(tmid[p1],tmid[p2]); tmid[p]=max(tmid[p],tr[p1]+tl[p2]); T[p]=T[p1]+T[p2]; if(T[p1]==mid-l+1) Tl[p]=Tl[p1]+Tl[p2];else Tl[p]=Tl[p1]; if(T[p2]==r-mid) Tr[p]=Tr[p2]+Tr[p1];else Tr[p]=Tr[p2]; Tmid[p]=max(Tmid[p1],Tmid[p2]); Tmid[p]=max(Tmid[p],Tr[p1]+Tl[p2]); } int main() { scanf("%d%d",&n,&m); for(i=1;i<=n;i++) scanf("%d",&a[i]); memset(add,-1,sizeof(add)); build(1,n,1); for(i=1;i<=m;i++) { scanf("%d%d%d",&p,&x,&y); x++;y++; if(p<=2) { update(1,n,x,y,p,1); } else { memset(ans,0,sizeof(ans)); solve(1,n,x,y,1,x); if(p==3) printf("%d\n",ans[1]);else printf("%d\n",ans[3]); } } return 0; }
一念起,天涯咫尺; 一念灭,咫尺天涯。