• 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
  • 相关阅读:
    (转)AS3中实现卡马克卷轴算法
    (转)flash位图缓存cacheAsBitmap
    (转)addFrameScript函数的纠结
    (转)flash安全策略文件
    (转)脏矩形技术学习
    (转)stopImmediatePropagation 和stopPropagation的区别
    (转)flash对象池技术
    揭开嵌入式C面试题背后的玄机
    一次遍历找链表倒数第n个节点
    N!的尾部连续0的个数
  • 原文地址:https://www.cnblogs.com/whatbeg/p/4057877.html
Copyright © 2020-2023  润新知