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
  • 相关阅读:
    SQLyog快捷键
    程序员常用工具下载地址及方式
    mysql基础命令
    Excel常用快捷键
    PS快捷键
    MySQL安装及配置
    Excel常用公式
    数据库函数
    mysql update语句的用法
    MySQL使用存储过程批量更新数据库所有表某个字段值
  • 原文地址:https://www.cnblogs.com/whatbeg/p/4057877.html
Copyright © 2011-2022 走看看