BZOJ1858[Scoi2010]序列操作 题解
2016-08-03 18:25
141 查看
题目大意:
有一个01序列,现在对于这个序列有五种变换操作和询问操作: 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。
思路:
维护每一段数的和、左端和右端以及整段中连续的0和1的长度,并使用标记进行下传。
代码:
有一个01序列,现在对于这个序列有五种变换操作和询问操作: 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。
思路:
维护每一段数的和、左端和右端以及整段中连续的0和1的长度,并使用标记进行下传。
代码:
#include<cstdio> #include<cstring> #include<iostream> #define N 400000 using namespace std; int root,num,cnt,lmax[2] ,rmax[2] ,mmax[2] ,sum ,tag[2] ,rev ,h ,t ,rc ,lc ,a ; void up_date(int x,int k) { int l=lc[x],r=rc[x]; lmax[k][x]=lmax[k][l],rmax[k][x]=rmax[k][r]; if (lmax[k][l]==t[l]-h[l]+1) lmax[k][x]+=lmax[k][r]; if (rmax[k][r]==t[r]-h[r]+1) rmax[k][x]+=rmax[k][l]; mmax[k][x]=max(max(mmax[k][l],mmax[k][r]),rmax[k][l]+lmax[k][r]); } void build(int l,int r,int &cur) { cur=++num,tag[0][cur]=tag[1][cur]=rev[cur]=0; h[cur]=l,t[cur]=r; if (l==r) { lc[cur]=rc[cur]=0; lmax[0][cur]=rmax[0][cur]=mmax[0][cur]=(a[l]==0); lmax[1][cur]=rmax[1][cur]=sum[cur]=mmax[1][cur]=(a[r]==1); return; } int mid=l+r>>1; build(l,mid,lc[cur]),build(mid+1,r,rc[cur]); up_date(cur,0),up_date(cur,1),sum[cur]=sum[lc[cur]]+sum[rc[cur]]; } void mark(int x,int k) { tag[k][x]=1,tag[k^1][x]=rev[x]=0,sum[x]=(t[x]-h[x]+1)*k; lmax[k][x]=rmax[k][x]=mmax[k][x]=t[x]-h[x]+1; lmax[k^1][x]=rmax[k^1][x]=mmax[k^1][x]=0; } void re(int x) { rev[x]^=1,sum[x]=t[x]-h[x]+1-sum[x]; swap(lmax[0][x],lmax[1][x]),swap(rmax[0][x],rmax[1][x]),swap(mmax[0][x],mmax[1][x]); } void push_down(int x) { if (tag[0][x]) mark(lc[x],0),mark(rc[x],0),tag[0][x]=0; if (tag[1][x]) mark(lc[x],1),mark(rc[x],1),tag[1][x]=0; if (rev[x]) re(lc[x]),re(rc[x]),rev[x]=0; } void change(int l,int r,int cur,int k) { if (h[cur]>r || t[cur]<l) return; if (h[cur]>=l && t[cur]<=r) { if (k<2) mark(cur,k); else re(cur); return; } push_down(cur); change(l,r,lc[cur],k),change(l,r,rc[cur],k); up_date(cur,0),up_date(cur,1),sum[cur]=sum[lc[cur]]+sum[rc[cur]]; } int ask1(int l,int r,int cur) { if (h[cur]>r || t[cur]<l) return 0; if (h[cur]>=l && t[cur]<=r) return sum[cur]; push_down(cur); return ask1(l,r,lc[cur])+ask1(l,r,rc[cur]); } int ask2(int l,int r,int cur) { if (l==h[cur] && r==t[cur]) return cur; int mid=h[cur]+t[cur]>>1; push_down(cur); if (r<=mid) return ask2(l,r,lc[cur]); else if (l>mid) return ask2(l,r,rc[cur]); else { int ans=++cnt; lc[ans]=ask2(l,mid,lc[cur]),rc[ans]=ask2(mid+1,r,rc[cur]); up_date(ans,0),up_date(ans,1),sum[ans]=sum[lc[ans]]+sum[rc[ans]]; return ans; } } int main() { int n,m,i,x,y,z; scanf("%d%d",&n,&m); for (i=1;i<=n;i++) scanf("%d",&a[i]); build(1,n,root); for (i=1;i<=m;i++) { scanf("%d%d%d",&z,&x,&y); x++,y++; if (z==3) printf("%d\n",ask1(x,y,root)); else if (z==4) cnt=num,printf("%d\n",mmax[1][ask2(x,y,root)]); else change(x,y,root,z); } return 0; }
相关文章推荐
- 【BZOJ 1858】 [Scoi2010]序列操作
- BZOJ 1858 [Scoi2010]序列操作 线段树
- bzoj 1858: [Scoi2010]序列操作 -- 线段树
- bzoj 1858: [Scoi2010]序列操作
- bzoj 1858: [Scoi2010]序列操作(线段树)
- BZOJ 1858 SCOI2010 序列操作 线段树
- 【BZOJ1858】【SCOI2010】序列操作(线段树+合并)
- 【BZOJ1858】[Scoi2010]序列操作 线段树
- 【bzoj1858】[Scoi2010]序列操作 线段树区间合并
- bzoj1858: [Scoi2010]序列操作
- bzoj1858: [Scoi2010]序列操作
- bzoj1858【scoi2010】序列操作
- BZOJ 1858: [Scoi2010]序列操作 [线段树]
- 【bzoj1858】【Scoi2010】序列操作【位运算】【卡常大法好】
- BZOJ 1858: [Scoi2010]序列操作( 线段树 )
- bzoj 1858: [Scoi2010] 序列操作 题解
- hdu3397 Sequence operation 线段树区间更新&&bzoj1858: [Scoi2010]序列操作
- 【分块】bzoj1858 [Scoi2010]序列操作
- bzoj1858 [Scoi2010]序列操作
- BZOJ 1858 SCOI 2010 序列操作