[SCOI2010]序列操作 (线段树区间合并)

地址:https://www.luogu.com.cn/problem/P2572

题意:

给一个序列,进行一下五种操作:

$1.$区间$[l,r]$全部变为$0$

$2.$区间$[l,r]$全部变为$1$

$3.$区间$[l,r]$内$0$全部变成$1$,$1$变成$0$

$4.$询问区间$[l,r]$内有多少个$1$

$5.$询问区间$[l,r]$内最多有多少个连续的$1$

思路:

首先,我们需要维护11个信息

$L:$区间左端点  $R:$区间右端点 $Sum:$区间和

$max[2]$:区间最大连续$0/1$的个数  $lmax[2]$:包含区间左端点的最大连续$0/1$个数 $rmax[2]$:包含区间右端点的最大连续$0/1$个数

$lazy$:区间覆盖信息,初始化为$-1$,表示区间未被覆盖  $rev:$ 区间翻转信息,表示区间是否应该翻转


 

现在考虑一下区间的合并$pushup$

区间合并时,主要考虑$lmax,rmax,max$这几个信息的合并

显然$t[rt].lmax=t[ls].max,t[rt].rmax=t[rs].max$

但是还要考虑左/右区间全为$0/1$的情况,如果有的话$t[rt].lmax+t[rs].lmax,t[rt].rmax+t[ls].rmax$

最后整个区间的最大值就为:左端点,右端点,合并后中间的最大值


再来考虑一下标记下沉$pushdown$,也是难点

对于标记下沉,通常我们应该两点:

$1.$标记的优先级

$2.$下放某一标记,是否会对其他标记产生影响

本题来说,区间覆盖的优先级高于区间翻转((因为先翻转再覆盖,翻转就会失去意义),在有区间覆盖标记的时候,应该将区间翻转标志直0

将区间赋值标记拆解时, 不仅需要将子区间赋值标记更新为此值, 还需要将子节点翻转标记清空

将区间翻转标记拆解时, 需要分两种情况考虑此标记下推对子区间 赋值标记 和 翻转标记造成的影响

考虑到赋值标记的优先级大于翻转标记, 在有赋值标记的情况下, 直接翻转赋值标记

其余情况翻转标记异或等于1

#include<iostream>
#include<algorithm>
#include<cstdio>
#define lid (id<<1)
#define rid (id<<1|1)
#define REP(i, x, y) for(int i = (x);i <= (y);i++)
 using namespace std;
 const int maxn=1e5+10;
 struct node{
     int l,r,sum,lazy,rev;
     int max[2],lmax[2],rmax[2];
 }tree[maxn<<2];
 int n,m,v[maxn];
    void pushup(int id){
    tree[id].sum = tree[lid].sum + tree[rid].sum;
    REP(i, 0, 1){
        tree[id].lmax[i] = tree[lid].lmax[i];
        if(i == 1 && tree[lid].sum == tree[lid].r - tree[lid].l + 1)//左区间全满
            tree[id].lmax[i] += tree[rid].lmax[i];//可以跨越
        else if(i == 0 && tree[lid].sum == 0)//左区间全空
            tree[id].lmax[i] += tree[rid].lmax[i];
        
        tree[id].rmax[i] = tree[rid].rmax[i];
        if(i == 1 && tree[rid].sum == tree[rid].r - tree[rid].l + 1)
            tree[id].rmax[i] += tree[lid].rmax[i];
        else if(i == 0 && tree[rid].sum == 0)
            tree[id].rmax[i] += tree[lid].rmax[i];
        
        tree[id].max[i] = tree[lid].rmax[i] + tree[rid].lmax[i];//中间
        tree[id].max[i] = max(tree[id].max[i], tree[lid].max[i]);//继承子区间
        tree[id].max[i] = max(tree[id].max[i], tree[rid].max[i]);
        }
    }
void build(int id, int l, int r){
    tree[id].l = l, tree[id].r = r, tree[id].lazy = -1;
    if(l == r){
        tree[id].sum = v[l];
        tree[id].max[0] = tree[id].lmax[0] = tree[id].rmax[0] = v[l] == 0;
        tree[id].max[1] = tree[id].lmax[1] = tree[id].rmax[1] = v[l] == 1;
        return ;
        }
    int mid = (l + r) >> 1;
    build(lid, l, mid), build(rid, mid + 1, r);
    pushup(id);
    }
void pushdown(int id){
    if(tree[id].lazy != -1){//优先级最高
        tree[id].rev = 0;//清空标记
        int val = tree[id].lazy;
        tree[lid].sum = (tree[lid].r - tree[lid].l + 1) * val;
        tree[rid].sum = (tree[rid].r - tree[rid].l + 1) * val;
        
        tree[lid].lazy = tree[rid].lazy = val;
        tree[lid].rev = tree[rid].rev = 0;
        
        tree[lid].max[val] 
        = tree[lid].lmax[val] 
        = tree[lid].rmax[val] 
        = tree[lid].r - tree[lid].l + 1;
        tree[lid].max[val ^ 1] 
        = tree[lid].lmax[val ^ 1] 
        = tree[lid].rmax[val ^ 1] 
        = 0;
        
        tree[rid].max[val] 
        = tree[rid].lmax[val] 
        = tree[rid].rmax[val] 
        = tree[rid].r - tree[rid].l + 1;
        tree[rid].max[val ^ 1] 
        = tree[rid].lmax[val ^ 1] 
        = tree[rid].rmax[val ^ 1] 
        = 0;
        
        tree[id].lazy = -1;
        }
    if(tree[id].rev){
        tree[lid].sum = (tree[lid].r - tree[lid].l + 1) - tree[lid].sum;
        tree[rid].sum = (tree[rid].r - tree[rid].l + 1) - tree[rid].sum;
        
        if(tree[lid].lazy != -1)tree[lid].lazy ^= 1;//综合考虑优先级, 对其他标记的影响
        else tree[lid].rev ^= 1;
        if(tree[rid].lazy != -1)tree[rid].lazy ^= 1;
        else tree[rid].rev ^= 1;
        
        swap(tree[lid].max[0], tree[lid].max[1]);
        swap(tree[lid].lmax[0], tree[lid].lmax[1]);
        swap(tree[lid].rmax[0], tree[lid].rmax[1]);
        
        swap(tree[rid].max[0], tree[rid].max[1]);
        swap(tree[rid].lmax[0], tree[rid].lmax[1]);
        swap(tree[rid].rmax[0], tree[rid].rmax[1]);
        
        tree[id].rev = 0;
        }
    }
void update(int id, int val, int l, int r){
    pushdown(id);
    if(tree[id].l == l && tree[id].r == r){
        if(val == 0 || val == 1){
            tree[id].sum = (tree[id].r - tree[id].l + 1) * val;
            tree[id].lazy = val;
            tree[id].max[val] 
            = tree[id].lmax[val] 
            = tree[id].rmax[val] 
            = tree[id].r - tree[id].l + 1;
            tree[id].max[val ^ 1] 
            = tree[id].lmax[val ^ 1] 
            = tree[id].rmax[val ^ 1] 
            = 0;
            }
        else if(val == 2){
            tree[id].sum = (tree[id].r - tree[id].l + 1) - tree[id].sum;
            tree[id].rev ^= 1;
            swap(tree[id].max[0], tree[id].max[1]);
            swap(tree[id].lmax[0], tree[id].lmax[1]);
            swap(tree[id].rmax[0], tree[id].rmax[1]);
            }
        return ;
        }
    int mid = (tree[id].l + tree[id].r) >> 1;
    if(mid < l)update(rid, val, l, r);
    else if(mid >= r)update(lid, val, l, r);
    else update(lid, val, l, mid), update(rid, val, mid + 1, r);
    pushup(id);
    }
int query(int id, int l, int r){
    pushdown(id);
    if(tree[id].l == l && tree[id].r == r)return tree[id].sum;
    int mid = (tree[id].l + tree[id].r) >> 1;
    if(mid < l)return query(rid, l, r);
    else if(mid >= r)return query(lid, l, r);
    else return query(lid, l, mid) + query(rid, mid + 1, r);
    }
node Q_max(int id, int l, int r){
    pushdown(id);
    if(tree[id].l == l && tree[id].r == r)return tree[id];
    int mid = (tree[id].l + tree[id].r) >> 1;
    if(mid < l)return Q_max(rid, l, r);
    else if(mid >= r)return Q_max(lid, l, r);
    else{
        node ret, L = Q_max(lid, l, mid), R = Q_max(rid, mid + 1, r);
        ret.sum = L.sum + R.sum;
        REP(i, 0, 1){
            ret.lmax[i] = L.lmax[i];
            if(i == 1 && L.sum == L.r - L.l + 1)//左区间全满
                ret.lmax[i] += R.lmax[i];//可以跨越
            else if(i == 0 && L.sum == 0)//左区间全空
                ret.lmax[i] += R.lmax[i];
            
            ret.rmax[i] = R.rmax[i];
            if(i == 1 && R.sum == R.r - R.l + 1)
                ret.rmax[i] += L.rmax[i];
            else if(i == 0 && R.sum == 0)
                ret.rmax[i] += L.rmax[i];
            
            ret.max[i] = L.rmax[i] + R.lmax[i];//中间
            ret.max[i] = max(ret.max[i], L.max[i]);//继承子区间
            ret.max[i] = max(ret.max[i], R.max[i]);
            }
        return ret;
        }
    }
 int main()
 {
     scanf("%d%d",&n,&m);
     for(int i=1;i<=n;i++) scanf("%d",&v[i]);
     build(1,1,n);
     while(m--){
         int op,l,r;
         scanf("%d%d%d",&op,&l,&r);
         l++,r++;
         if(op==0) update(1,0,l,r);
        else if(op==1) update(1,1,l,r);
        else if(op==2) update(1,2,l,r);
        else if(op==3) cout<<query(1,l,r)<<endl;
        else cout<<Q_max(1,l,r).max[1]<<endl;
     }
     return 0;
 }
View Code

 

posted @ 2020-06-12 16:17  overrate_wsj  阅读(137)  评论(0编辑  收藏  举报