[SCOI2010]序列操作
1858: [Scoi2010]序列操作
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 3213 Solved: 1548
[Submit][Status][Discuss]
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 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
Source
线段树大合集,头脑清醒就行了2333
唯一需要注意的一点是,我们对节点修改的时候,需要讨论翻转和覆盖的关系,这里我就不剧透了,你们自己想吧2333
#include<bits/stdc++.h> #define ll long long #define maxn 400005 using namespace std; int mxl[maxn][2],mxr[maxn][2]; int mx[maxn][2],tag[maxn],sum[maxn]; int n,m,a[maxn],le,ri,w,opt,qz,ans; inline void maintain(int o,int l,int r){ int mid=l+r>>1,lc=o<<1,rc=(o<<1)|1; sum[o]=sum[lc]+sum[rc]; if(sum[lc]==mid-l+1) mxl[o][1]=sum[lc]+mxl[rc][1],mxl[o][0]=0; else if(!sum[lc]) mxl[o][0]=mid-l+1+mxl[rc][0],mxl[o][1]=0; else mxl[o][0]=mxl[lc][0],mxl[o][1]=mxl[lc][1]; if(sum[rc]==r-mid) mxr[o][1]=sum[rc]+mxr[lc][1],mxr[o][0]=0; else if(!sum[rc]) mxr[o][0]=r-mid+mxr[lc][0],mxr[o][1]=0; else mxr[o][0]=mxr[rc][0],mxr[o][1]=mxr[rc][1]; mx[o][0]=max(mx[lc][0],max(mx[rc][0],mxr[lc][0]+mxl[rc][0])); mx[o][1]=max(mx[lc][1],max(mx[rc][1],mxr[lc][1]+mxl[rc][1])); } inline void change(int o,int l,int r,int TO){ if(TO<=2) tag[o]=TO; else{ if(tag[o]&&tag[o]<=2) tag[o]=3-tag[o]; else{ tag[o]=3-tag[o]; sum[o]=r-l+1-sum[o]; swap(mx[o][0],mx[o][1]); swap(mxl[o][0],mxl[o][1]); swap(mxr[o][0],mxr[o][1]); } } if(tag[o]==1){ sum[o]=mx[o][1]=mxl[o][1]=mxr[o][1]=0; mxl[o][0]=mx[o][0]=mxr[o][0]=r-l+1; } else if(tag[o]==2){ sum[o]=mx[o][1]=mxl[o][1]=mxr[o][1]=r-l+1; mxl[o][0]=mx[o][0]=mxr[o][0]=0; } } inline void pushdown(int o,int l,int r){ int mid=l+r>>1,lc=o<<1,rc=(o<<1)|1; if(tag[o]){ change(lc,l,mid,tag[o]); change(rc,mid+1,r,tag[o]); tag[o]=0; } } void build(int o,int l,int r){ if(l==r){ mx[o][a[l]]=mxl[o][a[l]]=mxr[o][a[l]]=1; sum[o]=a[l]; return; } int mid=l+r>>1,lc=o<<1,rc=(o<<1)|1; build(lc,l,mid),build(rc,mid+1,r); maintain(o,l,r); } void update(int o,int l,int r){ if(l>=le&&r<=ri){ change(o,l,r,opt); return; } int mid=l+r>>1,lc=o<<1,rc=(o<<1)|1; pushdown(o,l,r); if(le<=mid) update(lc,l,mid); if(ri>mid) update(rc,mid+1,r); maintain(o,l,r); } int querysum(int o,int l,int r){ if(l>=le&&r<=ri) return sum[o]; int mid=l+r>>1,lc=o<<1,rc=(o<<1)|1,an=0; pushdown(o,l,r); if(le<=mid) an+=querysum(lc,l,mid); if(ri>mid) an+=querysum(rc,mid+1,r); return an; } void query_continue(int o,int l,int r){ if(l>=le&&r<=ri){ ans=max(ans,max(mx[o][1],qz+mxl[o][1])); if(sum[o]==r-l+1) qz+=sum[o]; else qz=mxr[o][1]; return; } int mid=l+r>>1,lc=o<<1,rc=(o<<1)|1; pushdown(o,l,r); if(le<=mid) query_continue(lc,l,mid); if(ri>mid) query_continue(rc,mid+1,r); } inline void solve(){ while(m--){ scanf("%d%d%d",&opt,&le,&ri),le++,ri++; if(opt<=2){ opt++; update(1,1,n); } else if(opt==3) printf("%d\n",querysum(1,1,n)); else{ qz=ans=0; query_continue(1,1,n); printf("%d\n",ans); } } } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",a+i); build(1,1,n); solve(); return 0; }
我爱学习,学习使我快乐