zoukankan      html  css  js  c++  java
  • HDU 4902 Nice boat --线段树(区间更新)

    题意:给一个数字序列,第一类操作是将[l,r]内的数全赋为x ,第二类操作是将[l,r]中大于x的数赋为该数与x的gcd,若干操作后输出整个序列。

    解法: 本题线段树要维护的最重要的东西就是一个区间内所有数是否相等的标记。只维护这个东西都可以做出来。 我当时想歪了,想到维护Max[rt]表示该段的最大值,最大值如果<=x的话就不用更新了,但是好像加了这个“优化”跑的更慢了。

    我想大概是因为如果两个子树最大值或者整个两个子树的数不完全相等的话,根本不能直接下传这个值或者下传gcd,因为你不知道要更新哪个值。所以要维护一个区间是否相等的标记,而且这样最坏情况下也是更新到叶子节点,正好使我们要更新的。

    只要弄懂了要维护什么,其余的就不难了。

    代码1:(加一个Max标记)

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    #define N 100007
    
    int Max[4*N],mark[4*N];  //mark[rt]=-1表示此段值不统一,否则mark[rt]会等于该段的统一值
    
    int gcd(int a,int b)
    {
        if(!b) return a;
        return gcd(b,a%b);
    }
    
    void pushup(int rt)
    {
        Max[rt] = max(Max[2*rt],Max[2*rt+1]);
    }
    
    void pushdown(int l,int r,int rt)
    {
        if(mark[rt] != -1)  //此段值相同
        {
            mark[2*rt] = mark[2*rt+1] = mark[rt];
            Max[2*rt] = Max[2*rt+1] = Max[rt];
            mark[rt] = -1;
        }
    }
    
    void build(int l,int r,int rt)
    {
        mark[rt] = -1;
        if(l == r)
        {
            scanf("%d",&Max[rt]);
            mark[rt] = Max[rt];
            return;
        }
        int mid = (l+r)/2;
        build(l,mid,2*rt);
        build(mid+1,r,2*rt+1);
        pushup(rt);
    }
    
    void update(int l,int r,int aa,int bb,int val,int tag,int rt)
    {
        if(aa <= l && bb >= r)
        {
            if(tag == 1)
            {
                Max[rt] = mark[rt] = val;
                return;
            }
            else
            {
                if(mark[rt] != -1)    //此段值相等
                {
                    if(Max[rt] > val)    //要更新
                        Max[rt] = mark[rt] = gcd(mark[rt],val);
                    return;
                }
            }
        }
        pushdown(l,r,rt);
        int mid = (l+r)/2;
        if(aa <= mid) update(l,mid,aa,bb,val,tag,2*rt);
        if(bb > mid)  update(mid+1,r,aa,bb,val,tag,2*rt+1);
        pushup(rt);
    }
    
    void print(int l,int r,int rt)
    {
        if(l == r)
        {
            printf("%d ",Max[rt]);
            return;
        }
        pushdown(l,r,rt);
        int mid = (l+r)/2;
        print(l,mid,2*rt);
        print(mid+1,r,2*rt+1);
    }
    
    int main()
    {
        int n,m,i,t,tag,aa,bb,val;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d",&n);
            build(1,n,1);
            scanf("%d",&m);
            while(m--)
            {
                scanf("%d%d%d%d",&tag,&aa,&bb,&val);
                update(1,n,aa,bb,val,tag,1);
            }
            print(1,n,1);
            puts("");
        }
        return 0;
    }
    View Code

    代码2:(只维护一个)

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    #define N 100007
    
    int Max[4*N];
    
    int gcd(int a,int b)
    {
        if(!b) return a;
        return gcd(b,a%b);
    }
    
    void pushup(int rt)
    {
        if(Max[2*rt] == Max[2*rt+1]) Max[rt] = Max[2*rt];
    }
    
    void pushdown(int l,int r,int rt)
    {
        if(Max[rt] != -1)
            Max[2*rt] = Max[2*rt+1] = Max[rt], Max[rt] = -1;
    }
    
    void build(int l,int r,int rt)
    {
        Max[rt] = -1;
        if(l == r)
        {
            scanf("%d",&Max[rt]);
            return;
        }
        int mid = (l+r)/2;
        build(l,mid,2*rt);
        build(mid+1,r,2*rt+1);
        pushup(rt);
    }
    
    void update(int l,int r,int aa,int bb,int val,int tag,int rt)
    {
        if(aa <= l && bb >= r)
        {
            if(tag == 1)
            {
                Max[rt] = val;
                return;
            }
            else
            {
                if(Max[rt] != -1)
                {
                    if(Max[rt] > val)    //下面有比它大的,即有要更新的
                        Max[rt] = gcd(Max[rt],val);
                    return;
                }
            }
        }
        pushdown(l,r,rt);
        int mid = (l+r)/2;
        if(aa <= mid) update(l,mid,aa,bb,val,tag,2*rt);
        if(bb > mid)  update(mid+1,r,aa,bb,val,tag,2*rt+1);
        pushup(rt);
    }
    
    void print(int l,int r,int rt)
    {
        if(l == r)
        {
            printf("%d ",Max[rt]);
            return;
        }
        pushdown(l,r,rt);
        int mid = (l+r)/2;
        print(l,mid,2*rt);
        print(mid+1,r,2*rt+1);
    }
    
    int main()
    {
        int n,m,i,t,tag,aa,bb,val;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d",&n);
            build(1,n,1);
            scanf("%d",&m);
            while(m--)
            {
                scanf("%d%d%d%d",&tag,&aa,&bb,&val);
                update(1,n,aa,bb,val,tag,1);
            }
            print(1,n,1);
            puts("");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    2021年年度总结——命运与轮回思考
    Kafka消费端数据过滤方案
    Vue.js知识点汇集
    The POM for is missing .....no dependency information available
    Knife4j 自定义参数解析
    Java List<String> IndexOf(object e)坑
    ES6获取对象数组属性最大最小值
    VM虚拟机(Windows server 2019)分区
    uniapp本地文件的路径
    JS墨卡托坐标与经纬度互转
  • 原文地址:https://www.cnblogs.com/whatbeg/p/4057877.html
Copyright © 2011-2022 走看看