[Scoi2010]序列操作

Posted ~victorique~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Scoi2010]序列操作相关的知识,希望对你有一定的参考价值。

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

Sample Output

5
2
6
5

HINT

对于30%的数据,1<=n, m<=1000 对于100%的数据,1< = n, m < = 100000

Solution

深深感觉到重构代码的强大力量。

先来看看题目,满满的线段树的感觉,有多少个1比较好办,一个sum数组就能解决,那么连续的1用差分也可以比较容易的求出来。然后加上了翻转,导致这个题还要记录连续的0,记录左边的0右边的0,导致码量巨大,细节巨多。

说一下pushdown,那么可以发现的是覆盖标记比翻转标记来的等级高,因为覆盖了之后都变成一个数也不管你前面怎么翻转的了,所以我们在更改覆盖标记的时候要把它左右儿子的翻转标记一块覆盖掉。因此我们也要先进行覆盖操作再进行翻转,要不然这操作就没用了。。。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstring>
#include<algorithm>
#define ls rt<<1
#define rs rt<<1|1
#define re register
#define maxn 500007
using namespace std;
int a[maxn<<2];
struct node {
    int l,r,t;
} qmax;
struct tree {
    int tag0[maxn<<2],tag1[maxn<<2],rev[maxn<<2],l0[maxn<<2],r0[maxn<<2],l1[maxn<<2],r1[maxn<<2],add[maxn<<2],v[maxn<<2];
    int tag[maxn<<2];
    void pushup(int l,int r,int rt) {
        int mid=l+r>>1;
        v[rt]=v[ls]+v[rs];
        if(l1[ls]==mid-l+1) l1[rt]=l1[ls]+l1[rs];else l1[rt]=l1[ls];
        if(r1[rs]==r-mid) r1[rt]=r1[rs]+r1[ls];else r1[rt]=r1[rs];
        if(l0[ls]==mid-l+1) l0[rt]=l0[ls]+l0[rs];else l0[rt]=l0[ls];
        if(r0[rs]==r-mid) r0[rt]=r0[rs]+r0[ls];else r0[rt]=r0[rs];
        tag1[rt]=max(max(tag1[ls],tag1[rs]),l1[rs]+r1[ls]);
        tag0[rt]=max(max(tag0[ls],tag0[rs]),r0[ls]+l0[rs]);
    }
    void pushdown(int l,int r,int rt) {
        int mid=l+r>>1;
        if(tag[rt]!=-1) {
            tag[ls]=tag[rs]=tag[rt];
            v[ls]=tag1[ls]=l1[ls]=r1[ls]=(mid-l+1)*tag[rt];
            v[rs]=tag1[rs]=r1[rs]=l1[rs]=(r-mid)*tag[rt];
            tag0[ls]=r0[ls]=l0[ls]=(mid-l+1)*(tag[rt]^1);
            tag0[rs]=r0[rs]=l0[rs]=(r-mid)*(tag[rt]^1);
            rev[ls]=rev[rs]=0;tag[rt]=-1;
        }
        if(rev[rt]==1) {
            rev[rt]=0;
            v[ls]=(mid-l+1)-v[ls];v[rs]=(r-mid)-v[rs];
            swap(tag0[ls],tag1[ls]);swap(tag0[rs],tag1[rs]);
            swap(l0[ls],l1[ls]);swap(l0[rs],l1[rs]);
            swap(r0[ls],r1[ls]);swap(r0[rs],r1[rs]);
            rev[ls]^=1;rev[rs]^=1;
        }
    }
    void build(int l,int r,int rt) {
        tag[rt]=-1;
        if(l==r) {
            v[rt]=l1[rt]=r1[rt]=tag1[rt]=a[l];
            l0[rt]=r0[rt]=tag0[rt]=(a[l]^1);
            return;
        }
        int mid=l+r>>1;
        build(l,mid,ls);
        build(mid+1,r,rs);
        pushup(l,r,rt);
    }
    void change1(int L,int R,int k,int l,int r,int rt) {
        if(L<=l&&r<=R) {
            int qu=r-l+1;
            v[rt]=tag1[rt]=r1[rt]=l1[rt]=qu*k;
            tag0[rt]=r0[rt]=l0[rt]=qu*(k^1);
            tag[rt]=k;rev[rt]=0;
            return;
        }
        pushdown(l,r,rt);
        int mid=l+r>>1;
        if(L<=mid) change1(L,R,k,l,mid,ls);
        if(mid<R) change1(L,R,k,mid+1,r,rs);
        pushup(l,r,rt);
    }
    void change2(int L,int R,int l,int r,int rt) {
        if(L<=l&&r<=R) {
            int qu=r-l+1;
            v[rt]=qu-v[rt];
            swap(tag1[rt],tag0[rt]);
            swap(l1[rt],l0[rt]);
            swap(r1[rt],r0[rt]);
            rev[rt]^=1;
            return;
        }
        pushdown(l,r,rt);
        int mid=l+r>>1;
        if(L<=mid) change2(L,R,l,mid,ls);
        if(R>mid) change2(L,R,mid+1,r,rs);
        pushup(l,r,rt);
    }
    int ask1(int L,int R,int l,int r,int rt) {
        if(L<=l&&r<=R) return v[rt];
        pushdown(l,r,rt);
        if(l>R||r<L) return 0;
        int mid=l+r>>1;
        return ask1(L,R,l,mid,ls)+ask1(L,R,mid+1,r,rs);
    }
    node ask2(int L,int R,int l,int r,int rt) {
        if(L<=l&&r<=R) return(node) {
            l1[rt],r1[rt],tag1[rt]
        };
        pushdown(l,r,rt);
        node t,tl,tr;
        int fll=0,flr=0;
        int mid=l+r>>1;
        if(L<=mid) tl=ask2(L,R,l,mid,ls);
        else tl=(node) {0,0,0},fll=1;
        if(R>mid) tr=ask2(L,R,mid+1,r,rs);
        else tr=(node) {0,0,0},flr=1;
        if(tl.l==mid-l+1) t.l=tl.l+tr.l;
        else if(fll==1) t.l=tr.l;
        else t.l=tl.l;
        if(tr.r==r-mid) t.r=tr.r+tl.r;
        else if(flr==1) t.r=tl.r;
        else t.r=tr.r;
        t.t=max(max(tr.t,tl.t),tl.r+tr.l);
        return t;
    }
} T;
inline int read() {
    int x=0,c=1;
    char ch=' ';
    while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();
    while(ch=='-')c*=-1,ch=getchar(); 
    while(ch<='9'&&ch>='0')x=x*10+ch-'0',ch=getchar();
    return x*c;
}
int main() {
    int n,m;
    n=read();
    m=read();
    for(re int i=1; i<=n; i++)
        a[i]=read();
    T.build(1,n,1);
    for(re int i=1; i<=m; i++) {
//      for(re int j=1; j<=20; j++)
    //      cout<<T.l0[j]<<" "<<T.l1[j]<<" - "<<T.r0[j]<<" "<<T.r1[j]<<" - "<<T.tag0[j]<<" "<<T.tag1[j]<<" - "<<T.rev[j]<<" - "<<T.tag[j]<<" - "<<T.v[j]<<endl;
        int flag,x,y;
        flag=read();x=read();y=read();x++;y++;
        if(flag==0||flag==1) T.change1(x,y,flag,1,n,1);
        if(flag==2) T.change2(x,y,1,n,1);
        if(flag==3) printf("%d\n",T.ask1(x,y,1,n,1));
        if(flag==4) printf("%d\n",T.ask2(x,y,1,n,1).t);
    }
    return 0;
}

以上是关于[Scoi2010]序列操作的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 1858: [Scoi2010]序列操作

P2572 [SCOI2010]序列操作

[SCOI2010]序列操作

[SCOI2010]序列操作

[SCOI2010]序列操作

bzoj1858 [Scoi2010]序列操作