码迷,mamicode.com
首页 > 其他好文 > 详细

hdu 3397 Sequence operation (线段树 区间合并 多重标记)

时间:2018-10-13 02:20:56      阅读:219      评论:0      收藏:0      [点我收藏+]

标签:show   sequence   space   min   span   简单   ace   class   std   

链接;http://acm.hdu.edu.cn/showproblem.php?pid=3397

题意:

给你一串01串,有5种操作

0. 区间全部变为0

1.区间全部变为1

2.区间异或

3.询问区间1的个数

4.询问区间被最长连续1的长度

 

思路:

这5个操作都是比较基础的线段树操作,难点在于有两种修改操作,这类题之前也写过,之前是乘法和加法,这个是区间亦或和区间更新值,但是思路是可以借鉴的,我们要推出这两个操作的关系,这样才能维护好这两个标记,我们用两个标记:same , rev ,分别表示区间更新值和区间异或,那么向下更新的时候如果如果有same标记,清空当前区间的rev标记,简单维护下就好了,如果有rev标记,且有same标记,那么直接对same异或维护,如果没有same标记那么就维护下区间异或就好了。

 

写的超爽,一遍就a了,美滋滋,还以为又要找好久的错。。

 

实现代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define mid int m = (l + r) >> 1
#define ll long long

const int M = 1e5 + 10;
int lsum1[M<<2],rsum1[M<<2],sum1[M<<2];
int lsum0[M<<2],rsum0[M<<2],sum0[M<<2];
int sum[M<<2],same[M<<2],rev[M<<2];
int a[M];

void pushup(int l,int r,int rt){   
    mid;
    sum[rt] = sum[rt<<1] + sum[rt<<1|1];
    lsum0[rt] = lsum0[rt<<1]; lsum1[rt] = lsum1[rt<<1];
    rsum0[rt] = rsum0[rt<<1|1]; rsum1[rt] = rsum1[rt<<1|1];
    if(lsum0[rt] == m-l+1) lsum0[rt] += lsum0[rt<<1|1];
    if(rsum0[rt] == r-m) rsum0[rt] += rsum0[rt<<1];
    if(lsum1[rt] == m-l+1) lsum1[rt] += lsum1[rt<<1|1];
    if(rsum1[rt] == r-m) rsum1[rt] += rsum1[rt<<1];
    sum0[rt] = max(max(sum0[rt<<1],sum0[rt<<1|1]),lsum0[rt<<1|1]+rsum0[rt<<1]);
    sum1[rt] = max(max(sum1[rt<<1],sum1[rt<<1|1]),lsum1[rt<<1|1]+rsum1[rt<<1]);
}

void swa(int len,int rt){
    sum[rt] = len - sum[rt];
    swap(lsum1[rt],lsum0[rt]);
    swap(rsum1[rt],rsum0[rt]);
    swap(sum1[rt],sum0[rt]);
}

void pushdown(int l,int r,int rt){
    mid;
    if(same[rt]!=-1){
        rev[rt<<1] = rev[rt<<1|1] = 0;
        same[rt<<1] = same[rt<<1|1] = same[rt];
        if(same[rt]){
            sum[rt<<1] = lsum1[rt<<1] = rsum1[rt<<1] = sum1[rt<<1] = m-l+1;
            sum[rt<<1|1] = lsum1[rt<<1|1] = rsum1[rt<<1|1] = sum1[rt<<1|1] = r-m;
            lsum0[rt<<1] = rsum0[rt<<1] = sum0[rt<<1] = sum0[rt<<1|1] = rsum0[rt<<1|1] = lsum0[rt<<1|1] = 0;
        }
        else{
            sum[rt<<1] = lsum1[rt<<1] = rsum1[rt<<1] = sum1[rt<<1] = 0;
            sum[rt<<1|1] = lsum1[rt<<1|1] = rsum1[rt<<1|1] = sum1[rt<<1|1] = 0;
            lsum0[rt<<1] = rsum0[rt<<1] = sum0[rt<<1] = m-l+1;
            sum0[rt<<1|1] = rsum0[rt<<1|1] = lsum0[rt<<1|1] = r-m;
        }
        same[rt] = -1;
    }
    if(rev[rt]){
        if(same[rt<<1] != -1){
            same[rt<<1] ^= 1;
            if(same[rt<<1]){
                sum[rt<<1] = lsum1[rt<<1] = rsum1[rt<<1] = sum1[rt<<1] = m-l+1;
                lsum0[rt<<1] = rsum0[rt<<1] = sum0[rt<<1] = 0;
            }
            else{
                sum[rt<<1] = lsum1[rt<<1] = rsum1[rt<<1] = sum1[rt<<1] = 0;
                lsum0[rt<<1] = rsum0[rt<<1] = sum0[rt<<1] = m-l+1;
            }
        }
        else{
            rev[rt<<1] ^= 1;
            swa(m-l+1,rt<<1);
        }
        if(same[rt<<1|1] != -1){
            same[rt<<1|1] ^= 1;
            if(same[rt<<1|1]){
                sum[rt<<1|1] = lsum1[rt<<1|1] = rsum1[rt<<1|1] = sum1[rt<<1|1] = r-m;
                sum0[rt<<1|1] = rsum0[rt<<1|1] = lsum0[rt<<1|1] = 0;
            }
            else{
                sum[rt<<1|1] = lsum1[rt<<1|1] = rsum1[rt<<1|1] = sum1[rt<<1|1] = 0;
                sum0[rt<<1|1] = rsum0[rt<<1|1] = lsum0[rt<<1|1] = r-m;
            }
        }
        else{
            rev[rt<<1|1] ^= 1;
            swa(r-m,rt<<1|1);
        }
        rev[rt] = 0;
    }
}

void build(int l,int r,int rt){
    same[rt] = -1; rev[rt] = 0;
    lsum1[rt] = rsum1[rt] = lsum0[rt] = rsum0[rt] = sum0[rt] = sum1[rt] = sum[rt] = 0;
    if(l == r){
        if(a[l]){
            lsum1[rt] = sum[rt] = sum1[rt] = rsum1[rt] = 1;
            lsum0[rt] = rsum0[rt] = sum0[rt] = 0;
        }
        else {
            sum1[rt] = sum[rt] = sum1[rt] = rsum1[rt] = 0;
            lsum0[rt] = rsum0[rt] = sum0[rt] = 1;
        }
        return ;
    }
    mid ;
    build(lson); build(rson);
    pushup(l,r,rt);
}

void update_same(int L,int R,int c,int l,int r,int rt){
    if(L <= l&&R >= r){
        rev[rt] = 0;
        same[rt] = c;
        if(same[rt]){
            sum[rt] = lsum1[rt] = rsum1[rt] = sum1[rt] = r-l+1;
            lsum0[rt] = rsum0[rt] = sum0[rt] = 0;
        }
        else{
            sum[rt] = lsum1[rt] = rsum1[rt] = sum1[rt] = 0;
            lsum0[rt] = rsum0[rt] = sum0[rt] = r-l+1;
        }
        return ;
    }
    pushdown(l,r,rt);
    mid;
    if(L <= m) update_same(L,R,c,lson);
    if(R > m) update_same(L,R,c,rson);
    pushup(l,r,rt);
}

void update_rev(int L,int R,int l,int r,int rt){
    if(L <= l&&R >= r){
        if(same[rt] != -1){
            same[rt] ^= 1;
            if(same[rt]){
                sum[rt] = lsum1[rt] = rsum1[rt] = sum1[rt] = r-l+1;
                lsum0[rt] = rsum0[rt] = sum0[rt] = 0;
            }
            else{
                sum[rt] = lsum1[rt] = rsum1[rt] = sum1[rt] = 0;
                lsum0[rt] = rsum0[rt] = sum0[rt] = r-l+1;
            }
        }
        else{
            rev[rt] ^= 1;
            swa(r-l+1,rt);
        }
        return ;
    }
    mid ;
    pushdown(l,r,rt);
    if(L <= m) update_rev(L,R,lson);
    if(R > m) update_rev(L,R,rson);
    pushup(l,r,rt);
}

int query_sum(int L,int R,int l,int r,int rt){
    if(L <= l&&R >= r){
        return sum[rt];
    }
    pushdown(l,r,rt);
    mid;
    int ret = 0;
    if(L <= m) ret += query_sum(L,R,lson);
    if(R > m) ret += query_sum(L,R,rson);
    return ret;
}

int query_max(int L,int R,int l,int r,int rt){
    if(L <= l&&R >= r){
        return sum1[rt];
    }
    pushdown(l,r,rt);
    mid;
    int ret = 0;
    if(L > m) return query_max(L,R,rson);
    if(R <= m) return query_max(L,R,lson);
    int t1 = query_max(L,R,lson);
    int t2 = query_max(L,R,rson);
    int ls = min(rsum1[rt<<1],m-L+1);
    int rs = min(lsum1[rt<<1|1],R-m);
    return max(max(t1,t2),ls+rs);
}

int main()
{
    int n,q,x,y,op,t;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&q);
        for(int i = 1;i <= n;i ++)
            scanf("%d",&a[i]);
        build(1,n,1);
        while(q--){
            scanf("%d%d%d",&op,&x,&y);
            x++; y++;
            if(op == 0){
                update_same(x,y,0,1,n,1);
            }
            else if(op == 1){
                update_same(x,y,1,1,n,1);
            }
            else if(op == 2){
                update_rev(x,y,1,n,1);
            }
            else if(op == 3){
                printf("%d\n",query_sum(x,y,1,n,1));
            }
            else {
                printf("%d\n",query_max(x,y,1,n,1));
            }
        }
    }
    return 0;
}

 

hdu 3397 Sequence operation (线段树 区间合并 多重标记)

标签:show   sequence   space   min   span   简单   ace   class   std   

原文地址:https://www.cnblogs.com/kls123/p/9781070.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!