zoukankan      html  css  js  c++  java
  • 【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
    ",query(1,1,n,x,y));
    137         else if(op==4) printf("%d
    ",find(1,1,n,x,y).maxx[1]);
    138     }
    139     return 0;
    140 }
    AC Code
  • 相关阅读:
    再也不买仙剑正版盘了
    如果能边睡觉边上网多好
    不服
    <转>猛兽多是懒汉
    窗体中实现按 回车键 跳到下一个可选的TabIndex控件
    c# 索引器基础理论
    软件加密技术和注册机制入门介绍
    c# 属性 
    异常的一些基础知识
    关于MessageBox.Show的使用
  • 原文地址:https://www.cnblogs.com/shl-blog/p/10923723.html
Copyright © 2011-2022 走看看