• HDU5692 Snacks DFS序 线段树


    去博客园看该题解

    题目

    HDU5692 Snacks

    Problem Description

    百度科技园内有n个零食机,零食机之间通过n−1条路相互连通。每个零食机都有一个值v,表示为小度熊提供零食的价值。

    由于零食被频繁的消耗和补充,零食机的价值v会时常发生变化。小度熊只能从编号为0的零食机出发,并且每个零食机至多经过一次。另外,小度熊会对某个零食机的零食有所偏爱,要求路线上必须有那个零食机。

    为小度熊规划一个路线,使得路线上的价值总和最大。

    Input

    输入数据第一行是一个整数T(T≤10),表示有T组测试数据。

    对于每组数据,包含两个整数n,m(1≤n,m≤100000),表示有n个零食机,m次操作。

    接下来n−1行,每行两个整数x和y(0≤x,y<n),表示编号为x的零食机与编号为y的零食机相连。

    接下来一行由n个数组成,表示从编号为0到编号为n−1的零食机的初始价值v(|v|<100000)。

    接下来m行,有两种操作:0 x y,表示编号为x的零食机的价值变为y;1 x,表示询问从编号为0的零食机出发,必须经过编号为x零食机的路线中,价值总和的最大值。

    本题可能栈溢出,辛苦同学们提交语言选择c++,并在代码的第一行加上:

    `#pragma comment(linker, "/STACK:1024000000,1024000000") `

    Output

    对于每组数据,首先输出一行”Case #?:”,在问号处应填入当前数据的组数,组数从1开始计算。

    对于每次询问,输出从编号为0的零食机出发,必须经过编号为x零食机的路线中,价值总和的最大值。

    Sample Input

    1

    6 5

    0 1

    1 2

    0 3

    3 4

    5 3

    7 -5 100 20 -5 -7

    1 1

    1 3

    0 2 -1

    1 1

    1 5

    Sample Output

    Case #1:

    102

    27

    2

    20

    题目概括

    给定一棵n个点的有根树,每个点有一个点权。根节点为0,节点标号为0~n-1。

    定义最大路径为:从根出发走到某个点,点权和最大的路径。

    现在有Q次操作,每种是以下两种之一:

    (1).将点x的点权变成v。

    (2).求经过某一个点的最大路径的点权和。

    题解

    线段树。

    我们设:

    w[x]为节点x的权值

    Dis[x]为从根节点到达当前节点的权值

    那么,一开始,dis[x]可以通过一遍dfs全部求出来。

    如何处理更改和询问呢?那么我们从询问入手。

    题目询问的是经过一个点的最大路径的点权和,那么其实就是到达这个节点或者其子孙节点的最大dis[x], 其实就是查询整个子树的max(dis[x])。

    那么我们想到了什么?因为在树的dfs序中,同一个子树节点的所对应的序号一定是整个dfs序中的连续的一段!具体详见  关于dfs序的思考  。

    那么我们就可以把询问转化成“求区间最大值”的问题了。然而同理思考,那么修改其实就是修改整个子树的最大值!对于0 x y, 其实就是子树x的所有节点都增加y-w[x]!那么最大值也增加y-w[x]。

    问题就变成了一个询问区间最大值和区间修改(同增或者同减)的问题了。

    于是,我们就可以用线段树来维护。一棵线段树就好了吧。

    剧情还是有波折的!

    代码1 - TLE

     

    #pragma comment(linker, "/STACK:1024000000,1024000000")
    #include <cstring>
    #include <algorithm>
    #include <cstdlib>
    #include <cstdio>
    #include <vector>
    #define max(a,b) ((a)>(b)?(a):(b))
    using namespace std;
    typedef long long LL;
    const LL Inf=1e18;
    const int N=100000+5;
    vector <int> son[N];
    int T,n,m,time;
    int in[N],out[N];
    LL dis[N],w[N];
    struct Tree{
        LL add,v;
    }t[N*4];
    void dfs(int prev,int rt){
        in[rt]=++time;
        dis[in[rt]]=dis[in[prev]]+w[rt];
        for (int i=0;i<son[rt].size();i++)
            if (son[rt][i]!=prev)
                dfs(rt,son[rt][i]);
        out[rt]=time;
    }
    void build(int rt,int le,int ri){
        t[rt].add=0;
        if (le==ri){
            t[rt].v=dis[le];
            return;
        }
        int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1;
        build(ls,le,mid);
        build(rs,mid+1,ri);
        t[rt].v=max(t[ls].v,t[rs].v);
    }
    void pushdown(int rt){
        if (t[rt].add==0)
            return;
        int ls=rt<<1,rs=ls|1;
        LL v=t[rt].add;
        t[ls].v+=v,t[ls].add+=v;
        t[rs].v+=v,t[rs].add+=v;
        t[rt].add=0;
    }
    void update(int rt,int le,int ri,int xle,int xri,LL d){
        if (le>xri||xle>ri)
            return;
        if (xle<=le&&ri<=xri){
            t[rt].v+=d,t[rt].add+=d;
            return;
        }
        pushdown(rt);
        int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1;
        update(ls,le,mid,xle,xri,d);
        update(rs,mid+1,ri,xle,xri,d);
        t[rt].v=max(t[ls].v,t[rs].v);
    }
    LL query(int rt,int le,int ri,int xle,int xri){
        if (le>xri||xle>ri)
            return -Inf;
        if (xle<=le&&ri<=xri)
            return t[rt].v;
        pushdown(rt);
        int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1;
        LL ans=-Inf;
        ans=max(ans,query(ls,le,mid,xle,xri));
        ans=max(ans,query(rs,mid+1,ri,xle,xri));
        return ans;
    }
    int main(){
        scanf("%d",&T);
        for (int cas=1;cas<=T;cas++){
            scanf("%d%d",&n,&m);
            for (int i=0;i<N;i++)
                son[i].clear();
            for (int i=1,a,b;i<n;i++){
                scanf("%d%d",&a,&b),a++,b++;
                son[a].push_back(b);
                son[b].push_back(a);
            }
            for (int i=1;i<=n;i++)
                scanf("%lld",&w[i]);
            time=in[0]=dis[0]=0;
            dfs(0,1);
            build(1,1,n);
            printf("Case #%d:
    ",cas);
            while (m--){
                int type,x;
                LL y;
                scanf("%d%d",&type,&x),x++;
                if (type==0){
                    scanf("%lld",&y);
                    update(1,1,n,in[x],out[x],y-w[x]);
                    w[x]=y;
                }
                else
                    printf("%lld
    ",query(1,1,n,in[x],out[x]));
            }
        }
        return 0;
    }

    代码2 - AC

     

    #pragma comment(linker, "/STACK:1024000000,1024000000")
    #include <cstring>
    #include <cstdio>
    #include <cstdlib>
    #include <algorithm>
    #include <vector>
    using namespace std;
    typedef long long LL;
    const int N=100000+5;
    const LL Inf=1e18;
    vector <int> son[N];
    int T,n,m,in[N],out[N],time;
    LL w[N],dis[N];
    struct Tree{
        LL v,add;
    }t[N*4];
    void dfs(int prev,int rt){
        in[rt]=++time;
        dis[in[rt]]=dis[in[prev]]+w[rt];
        for (int i=0;i<son[rt].size();i++)
            if (son[rt][i]!=prev)
                dfs(rt,son[rt][i]);
        out[rt]=time;
    }
    void pushup(int rt){
        t[rt].v=max(t[rt<<1].v,t[rt<<1|1].v);
    }
    void build(int rt,int le,int ri){
        t[rt].add=0;
        if (le==ri){
            t[rt].v=dis[le];
            return;
        }
        int mid=(le+ri)>>1;
        build(rt<<1,le,mid);
        build(rt<<1|1,mid+1,ri);
        pushup(rt);
    }
    void pushdown(int rt){
        if (t[rt].add==0)
            return;
        int ls=rt<<1,rs=ls|1;
        LL v=t[rt].add;
        t[ls].v+=v,t[ls].add+=v;
        t[rs].v+=v,t[rs].add+=v;
        t[rt].add=0;
    }
    void update(int rt,int le,int ri,int xle,int xri,LL d){
        if (le>xri||ri<xle)
            return;
        if (xle<=le&&ri<=xri){
            t[rt].v+=d,t[rt].add+=d;
            return;
        }
        pushdown(rt);
        int mid=(le+ri)>>1;
        update(rt<<1,le,mid,xle,xri,d);
        update(rt<<1|1,mid+1,ri,xle,xri,d);
        pushup(rt);
    }
    LL query(int rt,int le,int ri,int xle,int xri){
        if (le>xri||ri<xle)
            return -Inf;
        if (xle<=le&&ri<=xri)
            return t[rt].v;
        pushdown(rt);
        int mid=(le+ri)>>1;
        return max(query(rt<<1,le,mid,xle,xri),query(rt<<1|1,mid+1,ri,xle,xri));
    }
    int main(){
        scanf("%d",&T);
        for (int cas=1;cas<=T;cas++){
            scanf("%d%d",&n,&m);
            for (int i=1;i<=n;i++)
                son[i].clear();
            for (int i=1,a,b;i<n;i++){
                scanf("%d%d",&a,&b);a++,b++;
                son[a].push_back(b);
                son[b].push_back(a);
            }
            for (int i=1;i<=n;i++)
                scanf("%lld",&w[i]);
            time=in[0]=dis[0]=0;
            dfs(0,1);
            build(1,1,n);
            printf("Case #%d:
    ",cas);
            while (m--){
                int type,x;
                LL y;
                scanf("%d%d",&type,&x);x++;
                if (type==0){
                    scanf("%lld",&y);
                    update(1,1,n,in[x],out[x],y-w[x]);
                    w[x]=y;
                }
                else
                    printf("%lld
    ",query(1,1,n,in[x],out[x]));
            }
        }
        return 0;
    }

    找不同~

    就是一句话的不同!

     

     

    #define max(a,b) ((a)>(b)?(a):(b))

    这句话!

    是的,我由于这句话苦苦寻找了10个小时,后来莫名其妙的过了~

    然后又找了1个小时,才发现是这句话……

    (UPD 2018-04-22):具体原因:如果你对宏定义有那么些了解,只需要把宏定义的内容代入到询问部分的return max(query(L),query(R))中,你就知道为什么是$O(n^2)$的了QAQ。代入结果为:return query(L)>query(R)?query(L):query(R)。这样的话,在第$k$层的询问就会被执行$O(2^k)$,而$2^k$的上限是$O(n)$级别的。所以单词询问就变成了$O(n)$的QAQ

    同时提醒同学们,千万不要傻傻的干这种事情了。

    附上一组数据:

    4
    9 5
    1 0
    1 2
    2 3
    4 1
    5 3
    6 5
    7 5
    7 8
    23182 80368 7060 -50161 81799 8841 90480 3016 -4312
    1 0
    0 8 -438497
    0 4 -188568
    1 4
    0 6 -176104

    9 4
    0 1
    0 2
    3 0
    3 4
    3 5
    6 1
    7 6
    0 8
    61060 -24449 -72783 -77927 -33421 80849 8262 -24364 90327
    0 2 116045
    0 5 404857
    1 2
    1 5

    7 8
    1 0
    0 2
    2 3
    4 2
    2 5
    6 1
    16405 -88702 4022 40275 80451 68322 78648
    0 3 -39689
    1 3
    0 3 100112
    0 2 109684
    1 6
    1 2
    0 3 -345744
    0 3 144465

    7 2
    0 1
    2 0
    0 3
    1 4
    5 0
    4 6
    -31521 32600 -32746 -67252 40896 94763 99624
    0 5 372906
    0 5 -118828

    ans:

    Case #1:
    185349
    -85018
    Case #2:
    177105
    387990
    Case #3:
    -19262
    6351
    226201
    Case #4:

  • 相关阅读:
    2018前端工程师成长路线图
    ECMAScript正则表达式6个最新特性
    Fundebug前端JavaScript插件更新至1.2.0
    写给前端工程师的10条实用原则
    代码面试需要知道的8种数据结构(附面试题及答案链接)
    20个Chrome DevTools调试技巧
    Web应用架构入门之11个基本要素
    配置Tree Shaking来减少JavaScript的打包体积
    SQL Server全文搜索(转载)
    ASP.NET Core多语言 (转载)
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/HDU5692.html
Copyright © 2020-2023  润新知