【SCOI2010】序列操作
做完这道题,我只想说:爽啊!
这道题的难点在于我们要支持区间赋值、区间翻转、区间最长子序列、区间求和这几种操作。
我们建一棵线段树,维护以下信息:
sum区间1的个数
max[0/1]区间内0/1最长连续子段
lmax[0/1]包含区间左端点最长0/1子段
rmax[0/1]包含区间右端点最长0/1子段
鉴于有区间操作, 这里还需要两个标记:
lazy = {-1, 0, 1}为-1表示无状态,为 0/1 表示区间全部赋值为0/1
rev = {0, 1}区间是否翻转
需要维护的元素较多, 先讲pushup
区间和直接相加即可
包含左端点的连续子段有两种情况:
直接继承左区间的lmax
当左区间全满 / 全空时, 左端点可以跨越, 加上右区间的部分
右区间更新同理
对于区间最长连续子段, 有以下三种情况
直接继承左区间的较大值
直接继承右区间的较大值
左区间的含右端点最长子段 + 右区间含左端点最长子段, 即最长部分跨越区间分割线
以上需要分0/1 讨论, 程序中直接两层循环搞定
然后到了难点pushdown
在线段树pushdown 操作中, 我们需要明确两件事:
1、标记的优先级
2、下放某一标记是否会对子节点的其他类型标记有所影响
这里重点讨论第二点(第一点区间全体赋值优先级肯定高于翻转, 所以优先拆区间赋值标记, 拆标记时需要将翻转标记清空)
在拆解一个标记时, 我们不仅需要明确将此标记下放到子节点, 同类型的标记应该如何改变, 而更应明确拆解此标记会对 不同类型的标记有何种影响
明确同类型的影响是一般不会出问题的, 如将区间加标记下放时, 子节点的区间加标记累加上这个值
以本题为例:
将区间赋值标记拆解时, 不仅需要将子区间赋值标记更新为此值, 还需要将子节点翻转标记清空(不过这个貌似影响不大, 拆赋值标记时会将翻转标记清空的)
将区间翻转标记拆解时, 需要分两种情况考虑此标记下推对子区间 赋值标记 和 翻转标记造成的影响
考虑到赋值标记的优先级大于翻转标记, 在有赋值标记的情况下, 直接翻转赋值标记
其余情况翻转标记异或等于1
详见代码
1 #include <iostream> 2 #include <cstdio> 3 using namespace std; 4 inline int read() { 5 int ret=0,op=1; 6 char c=getchar(); 7 while(c<'0'||c>'9') {if(c=='-') op=-1; c=getchar();} 8 while(c<='9'&&c>='0') ret=ret*10+c-'0',c=getchar(); 9 return ret*op; 10 } 11 int in[200010]; 12 struct node { 13 int ll,rr; 14 int sum,l[2],r[2],maxx[2]; 15 int rev,tag; 16 }a[200010<<2]; 17 int n,m; 18 inline void pushup(int now) { 19 a[now].sum=a[now<<1].sum+a[now<<1|1].sum; 20 for(int i=0;i<=1;i++) { 21 a[now].l[i]=a[now<<1].l[i]; 22 if(i==1&&a[now<<1].sum==a[now<<1].rr-a[now<<1].ll+1) a[now].l[i]+=a[now<<1|1].l[i]; 23 if(i==0&&a[now<<1].sum==0) a[now].l[i]+=a[now<<1|1].l[i]; 24 a[now].r[i]=a[now<<1|1].r[i]; 25 if(i==1&&a[now<<1|1].sum==a[now<<1|1].rr-a[now<<1|1].ll+1) a[now].r[i]+=a[now<<1].r[i]; 26 if(i==0&&a[now<<1|1].sum==0) a[now].r[i]+=a[now<<1].r[i]; 27 a[now].maxx[i]=max(a[now<<1].r[i]+a[now<<1|1].l[i],max(a[now<<1].maxx[i],a[now<<1|1].maxx[i])); 28 } 29 } 30 inline void pushdown(int now) { 31 if(a[now].tag!=-1) { 32 a[now].rev=0; 33 int num=a[now].tag; 34 a[now<<1].sum=num*(a[now<<1].rr-a[now<<1].ll+1); 35 a[now<<1|1].sum=num*(a[now<<1|1].rr-a[now<<1|1].ll+1); 36 a[now<<1].tag=a[now<<1|1].tag=num; 37 a[now<<1].rev=a[now<<1|1].rev=0; 38 a[now<<1].l[num]=a[now<<1].r[num]=a[now<<1].maxx[num]=a[now<<1].rr-a[now<<1].ll+1; 39 a[now<<1].l[num^1]=a[now<<1].r[num^1]=a[now<<1].maxx[num^1]=0; 40 a[now<<1|1].l[num]=a[now<<1|1].r[num]=a[now<<1|1].maxx[num]=a[now<<1|1].rr-a[now<<1|1].ll+1; 41 a[now<<1|1].l[num^1]=a[now<<1|1].r[num^1]=a[now<<1|1].maxx[num^1]=0; 42 a[now].tag=-1; 43 } 44 if(a[now].rev) { 45 a[now<<1].sum=(a[now<<1].rr-a[now<<1].ll+1)-a[now<<1].sum; 46 a[now<<1|1].sum=(a[now<<1|1].rr-a[now<<1|1].ll+1)-a[now<<1|1].sum; 47 if(a[now<<1].tag!=-1) a[now<<1].tag^=1; 48 else a[now<<1].rev^=1; 49 if(a[now<<1|1].tag!=-1) a[now<<1|1].tag^=1; 50 else a[now<<1|1].rev^=1; 51 swap(a[now<<1].l[1],a[now<<1].l[0]); swap(a[now<<1|1].l[1],a[now<<1|1].l[0]); 52 swap(a[now<<1].r[1],a[now<<1].r[0]); swap(a[now<<1|1].r[1],a[now<<1|1].r[0]); 53 swap(a[now<<1].maxx[1],a[now<<1].maxx[0]); swap(a[now<<1|1].maxx[1],a[now<<1|1].maxx[0]); 54 a[now].rev=0; 55 } 56 } 57 inline void build(int now,int l,int r) { 58 a[now].tag=-1; 59 a[now].ll=l; a[now].rr=r; 60 if(l==r) { 61 a[now].sum=in[l]; 62 a[now].l[0]=a[now].r[0]=a[now].maxx[0]=a[now].sum==0; 63 a[now].l[1]=a[now].r[1]=a[now].maxx[1]=a[now].sum==1; 64 return; 65 } 66 int mid=(l+r)>>1; 67 build(now<<1,l,mid); 68 build(now<<1|1,mid+1,r); 69 pushup(now); 70 } 71 void updata(int now,int l,int r,int x,int y,int val) { 72 pushdown(now); 73 if(x==l&&r==y) { 74 if(val==0||val==1) { 75 a[now].tag=val; 76 a[now].sum=val*(r-l+1); 77 a[now].l[val]=a[now].r[val]=a[now].maxx[val]=r-l+1; 78 a[now].l[val^1]=a[now].r[val^1]=a[now].maxx[val^1]=0; 79 } 80 else if(val==2) { 81 a[now].sum=(r-l+1)-a[now].sum; 82 a[now].rev^=1; 83 swap(a[now].l[1],a[now].l[0]); 84 swap(a[now].r[1],a[now].r[0]); 85 swap(a[now].maxx[1],a[now].maxx[0]); 86 } 87 return ; 88 } 89 int mid=(l+r)>>1; 90 if(y<=mid) updata(now<<1,l,mid,x,y,val); 91 else if(x>mid) updata(now<<1|1,mid+1,r,x,y,val); 92 else updata(now<<1,l,mid,x,mid,val),updata(now<<1|1,mid+1,r,mid+1,y,val); 93 pushup(now); 94 } 95 int query(int now,int l,int r,int x,int y) { 96 pushdown(now); 97 if(x==l&&r==y) return a[now].sum; 98 int mid=(l+r)>>1; 99 if(y<=mid) return query(now<<1,l,mid,x,y); 100 if(x>mid) return query(now<<1|1,mid+1,r,x,y); 101 return query(now<<1,l,mid,x,mid)+query(now<<1|1,mid+1,r,mid+1,y); 102 } 103 node find(int now,int l,int r,int x,int y) { 104 pushdown(now); 105 if(l==x&&y==r) return a[now]; 106 int mid=(l+r)>>1; 107 if(y<=mid) return find(now<<1,l,mid,x,y); 108 else if(x>mid) return find(now<<1|1,mid+1,r,x,y); 109 else { 110 node ret; 111 node retl=find(now<<1,l,mid,x,mid); 112 node retr=find(now<<1|1,mid+1,r,mid+1,y); 113 ret.sum=retl.sum+retr.sum; 114 for(int i=0;i<=1;i++) { 115 ret.l[i]=retl.l[i]; 116 if(i==1&&retl.sum==retl.rr-retl.ll+1) ret.l[i]+=retr.l[i]; 117 if(i==0&&retl.sum==0) ret.l[i]+=retr.l[i]; 118 ret.r[i]=retr.r[i]; 119 if(i==1&&retr.sum==retr.rr-retr.ll+1) ret.r[i]+=retl.r[i]; 120 if(i==0&&retr.sum==0) ret.r[i]+=retl.r[i]; 121 ret.maxx[i]=max(retl.r[i]+retr.l[i],max(retl.maxx[i],retr.maxx[i])); 122 } 123 return ret; 124 } 125 } 126 int main() { 127 n=read(); m=read(); 128 for(int i=1;i<=n;i++) in[i]=read(); 129 build(1,1,n); 130 while(m--) { 131 int op=read(),x=read(),y=read(); 132 x++; y++; 133 if(op==0) updata(1,1,n,x,y,0); 134 else if(op==1) updata(1,1,n,x,y,1); 135 else if(op==2) updata(1,1,n,x,y,2); 136 else if(op==3) printf("%d\n",query(1,1,n,x,y)); 137 else if(op==4) printf("%d\n",find(1,1,n,x,y).maxx[1]); 138 } 139 return 0; 140 }