zoukankan      html  css  js  c++  java
  • [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
  • 相关阅读:
    Graphviz安装配置
    固定ip
    机器学习基础
    研究生入学感悟
    复试临时练习
    复试临时练习
    Dev-C++回文数遇到的小麻烦
    单例模式
    工厂方法模式
    Spark的checkpoint详解
  • 原文地址:https://www.cnblogs.com/overrate-wsj/p/13100122.html
Copyright © 2011-2022 走看看