洛谷P2572 [SCOI2010]序列操作

@Pelom  October 12, 2021

题意

对于一个$01$序列,有$5$种操作:
$0 \ a \ b$ 把$[a,b]$区间内的所有数全变成$0$
$1 \ a \ b$ 把$[a,b]$区间内的所有数全变成$1$
$2 \ a \ b$ 把$[a,b]$区间内的所有数全部取反
$3 \ a \ b$ 询问$[a,b]$区间内总共有多少个$1$
$4 \ a \ b$ 询问$[a,b]$区间内最多有多少个连续的$1$
对于每个询问,输出答案

数据范围:$1 \le n,m \le 100000$

题解

明显的线段树题
需要维护哪些东西?区间$1$的总数,连续$1$的最大个数,覆盖标记,取反标记
为了在取反后获得连续$1$的最大个数,还需要维护连续$0$的最大个数
因为询问的是连续的$1$,在进行区间合并的时候,需要考虑以下情况

  1. 左区间的值
  2. 右区间的值
  3. 左区间的右端点可以和右区间的左端点接上

这样,还需要额外维护一个区间从左/右端点开始的连续$1$个数
而合并这两个东西也有特殊的情况,以从左开始为例,从右开始类似

  1. 左区间的值
  2. 左区间满,合并后为左区间的值$+$右区间从左开始的连续$1$个数

而因为区间取反的存在,同样需要同时维护这样的连续$0$个数

inline node operator + (const node& x){
    node res;
    res.c=c+x.c;
    res.l[0]=l[0];
    res.l[1]=l[1];
    if(s[0]==0)
        res.l[1]+=x.l[1];
    if(s[1]==0)
        res.l[0]+=x.l[0];
    res.r[0]=x.r[0];
    res.r[1]=x.r[1];
    if(x.s[0]==0)
        res.r[1]+=r[1];
    if(x.s[1]==0)
        res.r[0]+=r[0];
    res.s[0]=max(r[0]+x.l[0],max(s[0],x.s[0]));
    res.s[1]=max(r[1]+x.l[1],max(s[1],x.s[1]));
    return res;
}

下面是$pushdown$函数的写法
首先考虑两个标记的优先级问题:在区间覆盖后,区间取反会失效,所以优先处理区间覆盖;并在处理区间覆盖标记后,将区间取反标记置$0$
区间取反要交换维护的$0/1$的值,并将区间$1$个数更新为区间长度$-$区间$1$个数

inline void pushDown(int rt,int len){
    if(T[rt].v!=-1){
        T[ls].s[0]=T[ls].l[0]=T[ls].r[0]=(T[rt].v^1)*(len-(len>>1));
        T[ls].c=T[ls].s[1]=T[ls].l[1]=T[ls].r[1]=T[rt].v*(len-(len>>1));
        T[rs].s[0]=T[rs].l[0]=T[rs].r[0]=(T[rt].v^1)*(len>>1);
        T[rs].c=T[rs].s[1]=T[rs].l[1]=T[rs].r[1]=T[rt].v*(len>>1);
        T[ls].v=T[rs].v=T[rt].v;
        T[ls].f=T[rs].f=0;
        T[rt].v=-1;
    }
    if(T[rt].f){
        T[ls].c=(len-(len>>1))-T[ls].c;
        T[rs].c=(len>>1)-T[rs].c;
        swap(T[ls].s[0],T[ls].s[1]);
        swap(T[ls].l[0],T[ls].l[1]);
        swap(T[ls].r[0],T[ls].r[1]);
        swap(T[rs].s[0],T[rs].s[1]);
        swap(T[rs].l[0],T[rs].l[1]);
        swap(T[rs].r[0],T[rs].r[1]);
        T[ls].f^=1;
        T[rs].f^=1;
        T[rt].f=0;
    }
}

至此,本题复杂的操作完成,剩余部分与一般线段树无异

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define ls rt<<1
#define rs rt<<1|1
const int N=100000+10;
int n,m,op,a,b;
bool p[N];
struct node{
    int c,s[2],l[2],r[2];
    int v;
    bool f;
    inline node():c(0),s{0,0},l{0,0},r{0,0},v(-1),f(0){}
    inline node operator + (const node& x){
        node res;
        res.c=c+x.c;
        res.l[0]=l[0];
        res.l[1]=l[1];
        if(s[0]==0)
            res.l[1]+=x.l[1];
        if(s[1]==0)
            res.l[0]+=x.l[0];
        res.r[0]=x.r[0];
        res.r[1]=x.r[1];
        if(x.s[0]==0)
            res.r[1]+=r[1];
        if(x.s[1]==0)
            res.r[0]+=r[0];
        res.s[0]=max(r[0]+x.l[0],max(s[0],x.s[0]));
        res.s[1]=max(r[1]+x.l[1],max(s[1],x.s[1]));
        return res;
    }
} T[N<<2];
inline void pushUp(int rt){
    T[rt]=T[ls]+T[rs];
}
inline void pushDown(int rt,int len){
    if(T[rt].v!=-1){
        T[ls].s[0]=T[ls].l[0]=T[ls].r[0]=(T[rt].v^1)*(len-(len>>1));
        T[ls].c=T[ls].s[1]=T[ls].l[1]=T[ls].r[1]=T[rt].v*(len-(len>>1));
        T[rs].s[0]=T[rs].l[0]=T[rs].r[0]=(T[rt].v^1)*(len>>1);
        T[rs].c=T[rs].s[1]=T[rs].l[1]=T[rs].r[1]=T[rt].v*(len>>1);
        T[ls].v=T[rs].v=T[rt].v;
        T[ls].f=T[rs].f=0;
        T[rt].v=-1;
    }
    if(T[rt].f){
        T[ls].c=(len-(len>>1))-T[ls].c;
        T[rs].c=(len>>1)-T[rs].c;
        swap(T[ls].s[0],T[ls].s[1]);
        swap(T[ls].l[0],T[ls].l[1]);
        swap(T[ls].r[0],T[ls].r[1]);
        swap(T[rs].s[0],T[rs].s[1]);
        swap(T[rs].l[0],T[rs].l[1]);
        swap(T[rs].r[0],T[rs].r[1]);
        T[ls].f^=1;
        T[rs].f^=1;
        T[rt].f=0;
    }
}
void build(int rt,int l,int r){
    if(l==r){
        T[rt].c=T[rt].s[1]=T[rt].l[1]=T[rt].r[1]=p[l];
        T[rt].s[0]=T[rt].l[0]=T[rt].r[0]=p[l]^1;
        return ;
    }
    int mid=l+r>>1;
    build(ls,l,mid);
    build(rs,mid+1,r);
    pushUp(rt);
}
void update(int rt,int l,int r,int L,int R,int k){
    if(l>=L && r<=R){
        if(k==-1){
            T[rt].f^=1;
            T[rt].c=(r-l+1)-T[rt].c;
            swap(T[rt].s[0],T[rt].s[1]);
            swap(T[rt].l[0],T[rt].l[1]);
            swap(T[rt].r[0],T[rt].r[1]);
        }
        else{
            T[rt].s[0]=T[rt].l[0]=T[rt].r[0]=(k^1)*(r-l+1);
            T[rt].c=T[rt].s[1]=T[rt].l[1]=T[rt].r[1]=k*(r-l+1);
            T[rt].v=k;
            T[rt].f=0;
        }
        return ;
    }
    pushDown(rt,r-l+1);
    int mid=l+r>>1;
    if(L<=mid)
        update(ls,l,mid,L,R,k);
    if(R>mid)
        update(rs,mid+1,r,L,R,k);
    pushUp(rt);
}
node query(int rt,int l,int r,int L,int R){
    if(l>=L && r<=R){
        return T[rt];
    }
    pushDown(rt,r-l+1);
    node res;
    int mid=l+r>>1;
    if(L<=mid)
        res=res+query(ls,l,mid,L,R);
    if(R>mid)
        res=res+query(rs,mid+1,r,L,R);
    pushUp(rt);
    return res;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&p[i]);
    build(1,1,n);
    for(;m--;){
        scanf("%d%d%d",&op,&a,&b);
        a++,b++;
        switch(op){
            case 0:update(1,1,n,a,b,0);break;
            case 1:update(1,1,n,a,b,1);break;
            case 2:update(1,1,n,a,b,-1);break;
            case 3:printf("%d\n",query(1,1,n,a,b).c);break;
            case 4:printf("%d\n",query(1,1,n,a,b).s[1]);break;
        }
    }
    return 0;
}

添加新评论