• HDU 3397 Sequence operation (线段树)


    Sequence operation

    Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 4357    Accepted Submission(s): 1256


    Problem Description
    lxhgww got a sequence contains n characters which are all '0's or '1's.
    We have five operations here:
    Change operations:
    0 a b change all characters into '0's in [a , b]
    1 a b change all characters into '1's in [a , b]
    2 a b change all '0's into '1's and change all '1's into '0's in [a, b]
    Output operations:
    3 a b output the number of '1's in [a, b]
    4 a b output the length of the longest continuous '1' string in [a , b]
     
    Input
    T(T<=10) in the first line is the case number.
    Each case has two integers in the first line: n and m (1 <= n , m <= 100000).
    The next line contains n characters, '0' or '1' separated by spaces.
    Then m lines are the operations:
    op a b: 0 <= op <= 4 , 0 <= a <= b < n.
     
    Output
    For each output operation , output the result.
     
    Sample Input
    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
     
    Sample Output
    5 2 6 5
     
    Author
    lxhgww&&shǎ崽
     
    Source
     
    Recommend
    lcy

    题意:给个一只有0,1 的序列,有以下5种操作
    0 a b change all characters into '0's in [a , b] //把a,b间的都改为0
    1 a b change all characters into '1's in [a , b] //把a,b间都改为1
    2 a b change all '0's into '1's and change all '1's into '0's in [a, b] //1的改为0,0的改为1
    Output operations:
    3 a b output the number of '1's in [a, b]  //a,b间1 的数量
    4 a b output the length of the longest continuous '1' string in [a , b]//a,b间最大连续的1的个数

    思路:经典的线段树,只是操作过多,但其实很简单,相当于把以前做过的题的操作合在一块 什么值的更改,区间和的查询,最开连续的个数 。所以没什么特殊的

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    
    using namespace std;
    
    #define L(rt) (rt<<1)
    #define R(rt) (rt<<1|1)
    #define lson l,mid,rt<<1
    #define rson mid+1,r,rt<<1|1
    
    const int N=100010;
    
    int num[N];
    
    struct node{
        int l,r,len;    //len 是该区间的长度
        int sum,cover;  //sum 是该区间1的数量,cover 有3个值-1,0,1分别表示该区间是否被0,1完全覆盖
        int lm,rm,ma;   //lm rm ma 分别表示 左连续 右连续 和最大的连续1的个数
    }tree[N<<2];
    
    void PushUp(int rt){    //区间合并,由子结点修改父结点的信息
        tree[rt].sum=tree[L(rt)].sum+tree[R(rt)].sum;
        if(tree[L(rt)].len==tree[L(rt)].lm)
            tree[rt].lm=tree[L(rt)].len+tree[R(rt)].lm;
        else
            tree[rt].lm=tree[L(rt)].lm;
    
        if(tree[R(rt)].len==tree[R(rt)].rm)
            tree[rt].rm=tree[R(rt)].len+tree[L(rt)].rm;
        else
            tree[rt].rm=tree[R(rt)].rm;
    
        int a=max(tree[L(rt)].ma,tree[R(rt)].ma);
        int b=max(tree[rt].lm,tree[rt].rm);
        tree[rt].ma=max(max(a,b),tree[L(rt)].rm+tree[R(rt)].lm);
    }
    
    void build(int l,int r,int rt){
        tree[rt].l=l;
        tree[rt].r=r;
        tree[rt].len=r-l+1;
        tree[rt].cover=-1;
        if(l==r){
            if(num[l]){
                tree[rt].sum=1;
                tree[rt].cover=1;
                tree[rt].lm=tree[rt].rm=tree[rt].ma=1;
            }else{
                tree[rt].sum=0;
                tree[rt].cover=0;
                tree[rt].lm=tree[rt].rm=tree[rt].ma=0;
            }
            return ;
        }
        int mid=(l+r)>>1;
        build(lson);
        build(rson);
        PushUp(rt);
    }
    
    void PushDown(int rt){  //延迟操作,由父结点修改子结点
        tree[L(rt)].cover=tree[rt].cover;
        tree[R(rt)].cover=tree[rt].cover;
        if(tree[rt].cover){
            tree[L(rt)].lm=tree[L(rt)].rm=tree[L(rt)].ma=tree[L(rt)].len;
            tree[L(rt)].sum=tree[L(rt)].len;
            tree[R(rt)].lm=tree[R(rt)].rm=tree[R(rt)].ma=tree[R(rt)].len;
            tree[R(rt)].sum=tree[R(rt)].len;
        }else{
            tree[L(rt)].lm=tree[L(rt)].rm=tree[L(rt)].ma=0;
            tree[L(rt)].sum=0;
            tree[R(rt)].lm=tree[R(rt)].rm=tree[R(rt)].ma=0;
            tree[R(rt)].sum=0;
        }
        tree[rt].cover=-1;
    }
    
    void Update1(int flag,int l,int r,int rt){  //都是一个套路 左边,右边,或一起更新
        if(tree[rt].l==l && tree[rt].r==r){
            tree[rt].cover=flag;
            if(flag){
                tree[rt].lm=tree[rt].rm=tree[rt].ma=tree[rt].r-tree[rt].l+1;
                tree[rt].sum=tree[rt].ma;
            }else{
                tree[rt].lm=tree[rt].rm=tree[rt].ma=0;
                tree[rt].sum=0;
            }
            return ;
        }
        if(tree[rt].cover!=-1)
            PushDown(rt);
        int mid=(tree[rt].l+tree[rt].r)>>1;
        if(r<=mid)
            Update1(flag,l,r,L(rt));
        else if(l>=mid+1)
            Update1(flag,l,r,R(rt));
        else{
            Update1(flag,l,mid,L(rt));
            Update1(flag,mid+1,r,R(rt));
        }
        PushUp(rt);
    }
    
    void Update2(int l,int r,int rt){
        if(tree[rt].l==l && tree[rt].r==r && (tree[rt].sum==0 || tree[rt].sum==tree[rt].len)){
            if(tree[rt].sum>0){
                tree[rt].lm=tree[rt].rm=tree[rt].ma=0;
                tree[rt].sum=0;
                tree[rt].cover=0;
            }else{
                tree[rt].lm=tree[rt].rm=tree[rt].ma=tree[rt].len;
                tree[rt].sum=tree[rt].len;
                tree[rt].cover=1;
            }
            return ;
        }
        if(tree[rt].cover!=-1)
            PushDown(rt);
        int mid=(tree[rt].l+tree[rt].r)>>1;
        if(r<=mid)
            Update2(l,r,L(rt));
        else if(l>=mid+1)
            Update2(l,r,R(rt));
        else{
            Update2(l,mid,L(rt));
            Update2(mid+1,r,R(rt));
        }
        PushUp(rt);
    }
    
    int Query(int flag,int l,int r,int rt){ //查询操作 因为根据flag不同返回不同的值
        if(tree[rt].l==l && tree[rt].r==r){
            if(flag)
                return tree[rt].ma;
            else
                return tree[rt].sum;
        }
        if(tree[rt].cover!=-1)
            PushDown(rt);
        int mid=(tree[rt].l+tree[rt].r)>>1;
        if(r<=mid)
            return Query(flag,l,r,L(rt));
        else if(l>=mid+1)
            return Query(flag,l,r,R(rt));
        else{   //这是的return得注意,当返回 连续1的个数时 注意中间断开的情况
            if(flag){   //min (node[L(u)].rm,node[L(u)].r-left+1) 这是求左子结点右边最大的连续 右子结点同理
                int a=max(Query(flag,l,mid,L(rt)),Query(flag,mid+1,r,R(rt)));
                return max(a,min(tree[L(rt)].rm,tree[L(rt)].r-l+1)+min(tree[R(rt)].lm,r-tree[R(rt)].l+1));
            }else
                return (Query(flag,l,mid,L(rt))+Query(flag,mid+1,r,R(rt)));
        }
    }
    
    int main(){
    
        //freopen("input.txt","r",stdin);
    
        int t,n,m;
        scanf("%d",&t);
        while(t--){
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;i++)
                scanf("%d",&num[i]);
            build(1,n,1);
            int op,a,b;
            while(m--){
                scanf("%d%d%d",&op,&a,&b);
                a++;b++;
                if(op==0)
                    Update1(0,a,b,1);
                else if(op==1)
                    Update1(1,a,b,1);
                else if(op==2)
                    Update2(a,b,1);
                else if(op==3)
                    printf ("%d\n",Query(0,a,b,1));
                else
                    printf ("%d\n",Query(1,a,b,1));
            }
        }
        return 0;
    }
  • 相关阅读:
    hud 3336 count the string (KMP)
    JSOI2008星球大战(并查集)
    HAOI2006受欢迎的牛
    十二月个人考核
    十二月个人考核
    CentOS配置Tomcat监听80端口,虚拟主机
    CentOS配置Tomcat监听80端口,虚拟主机
    如何调试一个无法重现的错误?
    如何调试一个无法重现的错误?
    Highcharts的自适应DOM或者DIV,JS方法实现
  • 原文地址:https://www.cnblogs.com/jackge/p/3036990.html
Copyright © 2020-2023  润新知