【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 }
AC Code

 

posted @ 2019-05-25 20:11  AD_shl  阅读(257)  评论(0编辑  收藏  举报