zoukankan      html  css  js  c++  java
  • hdu 3397 Sequence Operation 线段树维护区间前后缀和,求子区间连续最值

    题目大意  链接http://acm.hdu.edu.cn/showproblem.php?pid=3397

      在一个由N个0或1构成的序列上进行五种操作:

        0 a b : 将区间[a,b]序列置为0

        1 a b : 将区间[a,b]序列置为1

        2 a b:  将区间[a,b]序列0,1互换

        3 a b:  输出区间[a,b] 为1的数量和

        4 a b:  输出区间[a,b] 连续1的最大长度

    解题思路

      分析题目的5种操作, 对于 0, 1, 3 操作,可以理解为区间覆盖,然后区间求和。这个对于普通的线段树是很好做的。

      对于 2,4 操作, 涉及到区间的旋转,以及子区间连续和。

      对于 子区间连续和的 询问, 我们可以通过 节点保存 前后缀和,区间最值,即可得到。

      对于区间的翻转操作,常规的作法可能是 splay tree 或者 treap , 不过这里可以不用。

      考虑到本题中,每个位置的值只能是1或者0, 则我们分别 对 0,1 做上面提到的  0,1,3,4 操作。

      等价于 两棵线段树,但是我们可以放到一起去。这里整体的思路就出来了。

      然后分析下细节问题:

        对于 0,1,3 的线段树常规操作这里就不做分析了。区间覆盖+区间求和。 SegTree的基本操作。

        首先分析 4操作,求子区间连续最大和

          对于节点 rt(l,r),其两个子节点为 lson, rson

          节点中应该存储四个信息:

            最大前缀和 Max_Light

            最大后缀和 Max_Right

            区间最大连续和 Max_Length

          则对于前缀和的维护为:

            节点rt前缀和 = Max{ 节点lson前缀和, 节点lson前缀和+节点rson前缀和(成立条件请自己想) }

          后缀和类似

          则对于区间最大连续和维护

            节点rt区间最大连续和 = Max{ lson最大连续和,rson最大连续和,lson后缀和+rson前缀和 }

          而对于查询的操作这里与通常线段树操作不同,查询区间[a,b]与区间[l,r] 之间存在9种情形,意味着有组合的情况。所以我们需要返回

    整个节点的信息,对于组合情况,我们应该组合成完整节点后再返回。

          另外提及一点,这种的处理方式,使用HH的线段树查询方式是不行的。因为其没有区分开不同情况。

          

          另外还要注意的细节部分是:

            一, push_UP操作中对于 前后缀和维护的地方

            二, 对于push_down 操作中, 覆盖与反置存在优先级的问题,覆盖应该优先,且发生覆盖后,反置则被清除掉。

    View Code
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    using namespace std;
    #define LL(x) ((x)<<1)
    #define RR(x) (((x)<<1) + 1)
    #define lson (rt<<1)
    #define rson ((rt<<1)|1)
    const int N = 100010;
    
    struct Tree{
        int l,r;
        int res, tag;
        int ml[2],mr[2],msum[2],mlen[2];    
    }tr[N<<2];
    
    int key[N]; 
    void push_up( int rt ){ 
        if( tr[rt].l == tr[rt].r ) return;
        for(int i = 0; i < 2; i++){
            if( tr[lson].msum[i^1] == 0 ) tr[rt].ml[i] = tr[lson].ml[i] + tr[rson].ml[i]; //此处应是1^i和 
            else    tr[rt].ml[i] = tr[lson].ml[i];
            if( tr[rson].msum[i^1] == 0 ) tr[rt].mr[i] = tr[rson].mr[i] + tr[lson].mr[i];
            else    tr[rt].mr[i] = tr[rson].mr[i];
            tr[rt].mlen[i] = max(  max(tr[lson].mlen[i],tr[rson].mlen[i]), tr[lson].mr[i]+tr[rson].ml[i] );
            tr[rt].msum[i] = tr[lson].msum[i] + tr[rson].msum[i];    
        }    
    }
    
    void push_down( int rt ){
        if( tr[rt].l == tr[rt].r ) return;
        if( tr[rt].tag != -1 ){ // 覆盖相对于 转换而言 优先级高 
            int type = tr[rt].tag;
            tr[lson].res = tr[rson].res = 0; // 若当前执行区间覆盖,前面出现的转换操作将被清除掉。 
            tr[lson].tag = tr[rson].tag = tr[rt].tag;
            tr[lson].ml[type] = tr[lson].mr[type] = tr[lson].mlen[type] = tr[lson].msum[type] = tr[lson].r-tr[lson].l+1;
            tr[lson].ml[type^1] = tr[lson].mr[type^1] = tr[lson].mlen[type^1] = tr[lson].msum[type^1] = 0;    
            tr[rson].ml[type] = tr[rson].mr[type] = tr[rson].mlen[type] = tr[rson].msum[type] = tr[rson].r-tr[rson].l+1;
            tr[rson].ml[type^1] = tr[rson].mr[type^1] = tr[rson].mlen[type^1] = tr[rson].msum[type^1] = 0;
            tr[rt].tag = -1;
        }
        if( tr[rt].res ){
            tr[lson].res ^= 1; tr[rson].res ^= 1;
            for(int i = 0; i < 2; i++){
                swap( tr[lson+i].ml[0], tr[lson+i].ml[1] );
                swap( tr[lson+i].mr[0], tr[lson+i].mr[1] );
                swap( tr[lson+i].msum[0], tr[lson+i].msum[1] );
                swap( tr[lson+i].mlen[0], tr[lson+i].mlen[1] );
            }
            tr[rt].res = 0;
        }
    }
    
    inline void build( int rt, int l, int r ){
        tr[rt].l = l, tr[rt].r = r, tr[rt].tag = -1, tr[rt].res = 0;
        if( l == r ){
            int x = key[l];
            tr[rt].ml[x] = tr[rt].mr[x] = tr[rt].msum[x] = tr[rt].mlen[x] = 1;
            tr[rt].ml[x^1] = tr[rt].mr[x^1] = tr[rt].msum[x^1] = tr[rt].mlen[x^1] = 0;
            return;
        }
        int mi = (l+r)>>1;
        build( lson, l, mi );
        build( rson, mi+1, r );
        push_up( rt );
    }
     
    
    inline void update( int rt, int l, int r, int type ){
        push_down( rt );
        if( tr[rt].l == l && tr[rt].r == r ){
            tr[rt].tag = type;
            tr[rt].ml[type] = tr[rt].mr[type] = tr[rt].msum[type] = tr[rt].mlen[type] = r-l+1;
            tr[rt].ml[type^1] = tr[rt].mr[type^1] = tr[rt].msum[type^1] = tr[rt].mlen[type^1] = 0;
            return;
        }
        int mi = (tr[rt].l+tr[rt].r)>>1;
        if( r <= mi ) update( lson, l, r, type );
        else if( mi < l ) update( rson , l ,r, type );
        else update( lson, l, mi, type ), update( rson, mi+1, r, type );
        
        push_up( rt );
    }
    
    
    inline void reverse(int rt,int l,int r){
    //    push_down( rt );
        if( tr[rt].l == l && tr[rt].r == r ){
            tr[rt].res ^= 1; // 转换 
            swap( tr[rt].ml[0], tr[rt].ml[1] );
            swap( tr[rt].mr[0], tr[rt].mr[1] );
            swap( tr[rt].mlen[0], tr[rt].mlen[1] );
            swap( tr[rt].msum[0], tr[rt].msum[1] );
            return;    
        }
        push_down( rt );
        int mi = (tr[rt].l+tr[rt].r)>>1;
        if( r <= mi ) reverse( lson, l, r );
        else if( mi < l ) reverse( rson, l, r );
        else reverse( lson, l, mi ),reverse( rson, mi+1, r ); 
        push_up(rt);
    }
    
    inline int query_sum(int rt,int l,int r){
    //    push_down( rt );
        if( l <= tr[rt].l && tr[rt].r <= r )
            return tr[rt].msum[1];
        push_down( rt );
        int mi = (tr[rt].l+tr[rt].r)>>1; 
        if( r <= mi ) return query_sum( lson, l, r );
        if( mi < l ) return query_sum( rson, l, r );
        return query_sum( lson, l, mi ) + query_sum( rson, mi+1, r );
    }
    
    inline Tree query_len(int rt,int l,int r){
        push_down( rt );
        if( tr[rt].l == l && tr[rt].r == r )
            return tr[rt];
        int mi = (tr[rt].l+tr[rt].r)>>1;
        if( r <= mi ) return query_len( lson, l, r );
        else if( mi < l ) return query_len( rson, l, r );
        else{
            Tree t1, t2, t;
            t1 = query_len( lson, l, mi );
            t2 = query_len( rson, mi+1, r );
            if( t1.ml[1] < (mi-l+1) ) t.ml[1] = t1.ml[1];
            else    t.ml[1] = t1.ml[1]+t2.ml[1];
            if( t2.mr[1] < (r-mi) ) t.mr[1] = t2.mr[1];
            else    t.mr[1] = t2.mr[1]+t1.mr[1];
            t.mlen[1] = max( max(t1.mlen[1],t2.mlen[1]), t1.mr[1]+t2.ml[1] );
            return t;
        }
    }
    
    int main(){
        int T, n, m;
        scanf("%d", &T);
        while( T-- ){
            scanf("%d%d", &n,&m);
            for(int i = 0; i < n; i++) scanf("%d", &key[i] );
            build( 1, 0, n-1 );
            int op, a, b;
            for(int i = 0; i < m; i++){
                scanf("%d%d%d",&op,&a,&b);
                if( op == 0 )    update( 1, a, b, 0 );
                else if( op == 1 ) update( 1, a, b, 1 );
                else if( op == 2 ) reverse( 1, a, b );
                else if( op == 3 ) printf("%d\n", query_sum( 1, a, b ) );
                else{
                    Tree ans = query_len( 1, a, b );
                    printf("%d\n", ans.mlen[1] );    
                }    
            }    
        }
        return 0;    
    }

    另还有一题,简单版,题目链接 http://acm.hrbust.edu.cn/index.php?m=ProblemSet&a=showProblem&problem_id=1684

      这里只需要处理区间连续最大和,没有反转操作。  

      一直WA..因为维护区间连续和时, 对于区间的值的处理.应该是 左儿子的区间和 + 右儿子的前缀和.....

    View Code
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    using namespace std;
     
    #define lson (rt<<1)
    #define rson (rt<<1|1) 
    const int N = 500010;
    typedef long long LL;
    
    struct Tree{
        int l, r;
        int lx, rx, ml, mr;
        LL lsum, rsum, msum, sum; 
    }tr[N<<2];
    int k[N];
     
    inline void push_up( int rt ){
        if( tr[rt].l == tr[rt].r ) return;
        tr[rt].sum = tr[lson].sum + tr[rson].sum;
        // WA 了好多次在这,  因为 lsum 不一定到 r,  rt.lsum = lson.sum+rson.lsum  左儿子的区间和 
        if( tr[lson].lsum < tr[lson].sum+tr[rson].lsum ) tr[rt].lsum = tr[lson].sum+tr[rson].lsum,tr[rt].lx = tr[rson].lx;     
        else    tr[rt].lsum = tr[lson].lsum, tr[rt].lx = tr[lson].lx;
        if( tr[rson].rsum < tr[rson].sum+tr[lson].rsum ) tr[rt].rsum = tr[rson].sum+tr[lson].rsum,tr[rt].rx = tr[lson].rx;
        else    tr[rt].rsum = tr[rson].rsum, tr[rt].rx = tr[rson].rx;
        
        tr[rt].msum = tr[lson].msum, tr[rt].ml = tr[lson].ml, tr[rt].mr = tr[lson].mr;
        if( tr[rt].msum <= tr[lson].rsum+tr[rson].lsum ){ 
            if( (tr[rt].msum == tr[lson].rsum+tr[rson].lsum) && (tr[rt].ml > tr[lson].rx) )
                tr[rt].ml = tr[lson].rx, tr[rt].mr = tr[rson].lx;
            else if( tr[rt].msum < tr[lson].rsum+tr[rson].lsum )
                tr[rt].msum = tr[lson].rsum + tr[rson].lsum, tr[rt].ml = tr[lson].rx, tr[rt].mr = tr[rson].lx;    
        }
        if( tr[rt].msum < tr[rson].msum )
            tr[rt].msum = tr[rson].msum, tr[rt].ml = tr[rson].ml, tr[rt].mr = tr[rson].mr;
        
    //    tr[rt].msum = max( max(tr[lson].msum,tr[rson].msum), tr[lson].rsum+tr[rson].lsum ); 
        
    //    printf("rt = %d, (%d,%d)\n", rt, tr[rt].l, tr[rt].r );
    //    printf("Sum:(%I64d,%I64d,%I64d)\n", tr[rt].lsum, tr[rt].msum, tr[rt].rsum );
    //    printf("idx:(%d,%d),[%d,%d]\n", tr[rt].lx, tr[rt].rx, tr[rt].ml, tr[rt].mr );
    //    printf("lsum = %I64d, rsum = %I64d, msum = %I64d\n", tr[rt].lsum, tr[rt].rsum, tr[rt].msum );
    } 
    void build( int rt, int l, int r ){
        tr[rt].l = l, tr[rt].r = r; 
        if( l == r ){
            tr[rt].lsum = tr[rt].rsum = tr[rt].msum = tr[rt].sum = k[l];
            tr[rt].lx = tr[rt].rx = tr[rt].ml = tr[rt].mr = l; 
            return; 
        }
        int m = (l+r)>>1;
        build( lson, l, m );
        build( rson, m+1, r );
        push_up(rt); 
    }
    
    inline Tree query( int rt, int l, int r ){
        if( tr[rt].l == l && tr[rt].r == r ) 
            return tr[rt];
        int m = (tr[rt].l+tr[rt].r)>>1;
        if( r <= m ) return query( lson, l, r );
        else if( m < l ) return query( rson, l, r );
        else{
            Tree t1, t2, t;
            t1 = query( lson, l, m );
            t2 = query( rson, m+1, r );
            t.sum = t1.sum + t2.sum;
            if( t1.lsum < t1.sum+t2.lsum ) t.lsum = t1.sum+t2.lsum, t.lx = t2.lx; 
            else    t.lsum = t1.lsum, t.lx = t1.lx;
            if( t2.rsum < t2.sum+t1.rsum ) t.rsum = t2.sum+t1.rsum, t.rx = t1.rx; 
            else    t.rsum = t2.rsum, t.rx = t2.rx;
             
            t.msum = t1.msum, t.ml = t1.ml, t.mr = t1.mr;
    
            if( t.msum <= t1.rsum+t2.lsum ){
                if( (t.msum == t1.rsum+t2.lsum) && (t.ml > t1.rx) )
                    t.ml = t1.rx, t.mr = t2.lx;
                else if( t.msum < t1.rsum+t2.lsum )
                    t.msum = t1.rsum + t2.lsum, t.ml = t1.rx, t.mr = t2.lx;     
            }
            if( t.msum < t2.msum )
                t.msum = t2.msum, t.ml = t2.ml, t.mr = t2.mr; 
            
            //t.msum = max( max(t1.msum,t2.msum), t1.rsum+t2.lsum );    
            t.l = l, t.r = r; 
            return t; 
        }
    } 
    int main(){
        freopen("in.txt","r",stdin);
        freopen("test.txt","w",stdout);
        int T, n, m;
        scanf("%d", &T);
        while( T-- ){
            scanf("%d%d", &n,&m);
            for(int i = 1; i <= n; i++)
                scanf("%d", &k[i] ); 
            build(1,1,n);
            int a, b;
            for(int i = 0; i < m; i++){
                scanf("%d%d",&a,&b);
                Tree t = query( 1, a, b ); 
        //        printf("msum = %I64d, ml = %d, mr = %d\n", t.msum, t.ml, t.mr ); 
                printf("%d %d\n", t.ml, t.mr );
            }      
        } 
        return 0;    
    }
  • 相关阅读:
    java.lang.NoSuchMethodError: org.springframework.core.io.ResourceEditor错误
    http://blog.sina.com.cn/s/blog_6145ed810102vr8k.html
    异或巧用:Single Number
    Highcharts:X轴分组堆叠图
    Vs2012在Linux开发中的应用(5):项目属性的定义
    BZOJ 1005 明明的烦恼 Prufer序列+组合数学+高精度
    Python 点滴 I
    easyUI 验证控件应用、自己定义、扩展验证 手机号码或电话话码格式
    InnoDB: Error: io_setup() failed with EAGAIN after 5 attempts
    Java设计模式-设计模式的六种原则
  • 原文地址:https://www.cnblogs.com/yefeng1627/p/2984787.html
Copyright © 2011-2022 走看看