zoukankan      html  css  js  c++  java
  • P2572 [SCOI2010]序列操作 线段树

      

    题目描述

    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都需要给出回答,聪明的程序员们,你们能帮助他吗?

    输入输出格式

    输入格式:

    输入数据第一行包括2个数,n和m,分别表示序列的长度和操作数目

    第二行包括n个数,表示序列的初始状态

    接下来m行,每行3个数,op, a, b,(0<=op<=4,0<=a<=b<n)表示对于区间[a, b]执行标号为op的操作

    输出格式:

    对于每一个询问操作,输出一行,包括1个数,表示其对应的答案

    输入输出样例

    输入样例#1: 复制
    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

    题目描述

    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都需要给出回答,聪明的程序员们,你们能帮助他吗?

    输入输出格式

    输入格式:

    输入数据第一行包括2个数,n和m,分别表示序列的长度和操作数目

    第二行包括n个数,表示序列的初始状态

    接下来m行,每行3个数,op, a, b,(0<=op<=4,0<=a<=b<n)表示对于区间[a, b]执行标号为op的操作

    输出格式:

    对于每一个询问操作,输出一行,包括1个数,表示其对应的答案

    输入输出样例

    输入样例#1: 复制
    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
    
    输出样例#1: 复制
    5
    2
    6
    5


    这些操作都比较简单 之前都学过
    但是加在一起就会产生一个问题 那就是翻转标记和区间修改标记的顺序该如何处理 先反转和先修改的操作是不一样的


    修改操作的优先级是比翻转操作的优先级高的

    在update里
    对一个点先后两次操作一共有四种方法
    1.先反转后修改
    显然 翻转的操作已经被覆盖掉了 所以在设置修改懒标记的时候如果有翻转标记直接清空掉

    2.先修改后翻转
    正常处理

    3.4没有问题

    在down里
    先处理修改的 因为修改的优先级高(先反转后修改的操作已经被覆盖掉了 也就是反转标记已经被清零)
    下推懒标记的时候如果下面的两个儿子有翻转标记的话要清空
    然后处理翻转标记即可


    非常好的线段树 加深了理解
    #include<bits/stdc++.h>
    using namespace std;
    //input by bxd
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define repp(i,a,b) for(int i=(a);i>=(b);--i)
    #define RI(n) scanf("%d",&(n))
    #define RII(n,m) scanf("%d%d",&n,&m)
    #define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
    #define RS(s) scanf("%s",s)
    #define ll long long
    #define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
    #define pb push_back
    #define inf 0x3f3f3f3f
    #define lson l,m,pos<<1
    #define rson m+1,r,pos<<1|1
    #define CLR(A,v)  memset(A,v,sizeof A)
    typedef pair<int,int>pii;
    //////////////////////////////////
    const int N=1e5+10;
    int tsum[N<<2],t0[N<<2],t1[N<<2],ri0[N<<2],ri1[N<<2],le0[N<<2],le1[N<<2],len[N<<2],col[N<<2],rev[N<<2];
    int num[N];
    void up(int pos)
    {
        tsum[pos]=tsum[pos<<1]+tsum[pos<<1|1];// 区间求和
        t0[pos]=max( max(t0[pos<<1],t0[pos<<1|1]),ri0[pos<<1]+le0[pos<<1|1]  );
        t1[pos]=max( max(t1[pos<<1],t1[pos<<1|1]),ri1[pos<<1]+le1[pos<<1|1]  );
    
        if(le1[pos<<1]==len[pos<<1])
        le1[pos]=le1[pos<<1]+le1[pos<<1|1];
        else le1[pos]=le1[pos<<1];
    
        if(le0[pos<<1]==len[pos<<1])
        le0[pos]=le0[pos<<1]+le0[pos<<1|1];
        else le0[pos]=le0[pos<<1];
    
        if(ri1[pos<<1|1]==len[pos<<1|1])
        ri1[pos]=ri1[pos<<1|1]+ri1[pos<<1];
        else ri1[pos]=ri1[pos<<1|1];
    
        if(ri0[pos<<1|1]==len[pos<<1|1])
        ri0[pos]=ri0[pos<<1|1]+ri0[pos<<1];
        else ri0[pos]=ri0[pos<<1|1];
    }
    void build(int l,int r,int pos)
    {
        len[pos]=r-l+1;
        if(l==r){ tsum[pos]=num[l]; le0[pos]=ri0[pos]=t0[pos]=(num[l]==0);  le1[pos]=ri1[pos]=t1[pos]=(num[l]==1); return ;}
        int m=(l+r)>>1;build(lson);build(rson);up(pos);
    }
    void down(int m,int pos)
    {
        if(col[pos]!=-1)// 修改会覆盖翻转
        {
            rev[pos<<1]=rev[pos<<1|1]=0;//覆盖翻转
            col[pos<<1]=col[pos<<1|1]=col[pos];//标记传递
    
            if(col[pos]==1){
            t1[pos<<1]=tsum[pos<<1]=le1[pos<<1]=ri1[pos<<1]=len[pos<<1];
            t1[pos<<1|1]=tsum[pos<<1|1]=le1[pos<<1|1]=ri1[pos<<1|1]=len[pos<<1|1];
            t0[pos<<1]=t0[pos<<1|1]=le0[pos<<1]=le0[pos<<1|1]=ri0[pos<<1]=ri0[pos<<1|1]=0;}
            else if(col[pos]==0){
            t0[pos<<1]=le0[pos<<1]=ri0[pos<<1]=len[pos<<1];
            t0[pos<<1|1]=le0[pos<<1|1]=ri0[pos<<1|1]=len[pos<<1|1];
            tsum[pos<<1]=tsum[pos<<1|1]=le1[pos<<1]=le1[pos<<1|1]=ri1[pos<<1]=ri1[pos<<1|1]=t1[pos<<1]=t1[pos<<1|1]=0;}
            
            col[pos]=-1;
        }
        if(rev[pos])
        {
            tsum[pos<<1]=len[pos<<1]-tsum[pos<<1];
            tsum[pos<<1|1]=len[pos<<1|1]-tsum[pos<<1|1];
    
            swap(le1[pos<<1],le0[pos<<1]);
            swap(le1[pos<<1|1],le0[pos<<1|1]);
            swap(ri1[pos<<1],ri0[pos<<1]);
            swap(ri1[pos<<1|1],ri0[pos<<1|1]);
            swap(t1[pos<<1],t0[pos<<1]);
            swap(t1[pos<<1|1],t0[pos<<1|1]);//翻转01最大连续长度
    
            rev[pos<<1]^=1;rev[pos<<1|1]^=1;
            rev[pos]=0;
        }
    }
    void upsum(int L,int R,int v,int l,int r,int pos)
    {
        if(L<=l&&r<=R)
        {
            col[pos]=v;rev[pos]=0;tsum[pos]=v*(r-l+1);
            t1[pos]=le1[pos]=ri1[pos]=v*(r-l+1);
            t0[pos]=le0[pos]=ri0[pos]=(v^1)*(r-l+1);
            return ;
        }int m=(l+r)>>1;down(r-l+1,pos);
        if(L<=m)upsum(L,R,v,lson);if(R>m)upsum(L,R,v,rson);up(pos);
    }
    void uprev(int L,int R,int l,int r,int pos)
    {
        if(L<=l&&r<=R)
        {
            rev[pos]^=1;
            tsum[pos]=r-l+1-tsum[pos];
            swap(t1[pos],t0[pos]);
            swap(le1[pos],le0[pos]);
            swap(ri1[pos],ri0[pos]);
            return ;
        }int m=(l+r)>>1;down(r-l+1,pos);
        if(L<=m)uprev(L,R,lson);if(R>m)uprev(L,R,rson);up(pos);
    }
    int qsum(int L,int R,int l,int r,int pos)
    {
        if(L<=l&&r<=R)return tsum[pos];
        int ans=0;int m=(l+r)>>1;down(r-l+1,pos);
        if(L<=m)ans+=qsum(L,R,lson);if(R>m)ans+=qsum(L,R,rson);
        return ans;
    }
    int qmax(int L,int R,int l,int r,int pos)
    {
        if(L<=l&&r<=R)return t1[pos];
        int m=(l+r)>>1;
        down(r-l+1,pos);
    
        if(L<=m&&R>m)
        {
            int ans=max(qmax(L,R,lson),qmax(L,R,rson)),rm,lm;
            rm=min((m-L+1),ri1[pos<<1] );
            lm=min((R-m),le1[pos<<1|1]);
            ans=max(ans,rm+lm);return ans;
        }
        else if(L<=m)return qmax(L,R,lson);
        else if(R>m)return qmax(L,R,rson);
    }
    int n,m,a,b,c;
    int main()
    {
        CLR(col,-1);
        RII(n,m);
        rep(i,1,n)RI(num[i]);
    
        build(1,n,1);
        while(m--)
        {
            RIII(c,a,b);a++,b++;
            if(c==0)upsum(a,b,0,1,n,1);
            if(c==1)upsum(a,b,1,1,n,1);
            if(c==2)uprev(a,b,1,n,1);
            if(c==3)printf("%d
    ",qsum(a,b,1,n,1));
            if(c==4)printf("%d
    ",qmax(a,b,1,n,1));
        }
        return 0;
    }
    View Code








































    0 5 6 3 3 9
    输出样例#1: 复制
    5
    2
    6
    5








  • 相关阅读:
    vim在插入模式下的粘贴
    关于外语学习的7个“美丽误会”(图)
    美国在线教育的启示:教育领域正在革命
    自动生成计算题
    字符串的截取,分割,替换
    将字符串转成byte,然后再转回来 日期相互转化字符串
    java编写的万年历代码
    小球弹砖块游戏(JAVA)
    随即输入一段字符串,统计出数字,大写字母。小写字母,空格
    邮箱验证信息
  • 原文地址:https://www.cnblogs.com/bxd123/p/11201267.html
Copyright © 2011-2022 走看看