hdu5834 Magic boy Bi Luo with his excited tree(树形dp)

Magic boy Bi Luo with his excited tree

Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)

Total Submission(s): 723    Accepted Submission(s): 192

Problem Description

Bi Luo is a magic boy, he also has a migic tree, the tree has N nodes
, in each node , there is a treasure, it‘s value is V[i],
and for each edge, there is a cost C[i],
which means every time you pass the edge i ,
you need to pay C[i].

You may attention that every V[i] can
be taken only once, but for some C[i] ,
you may cost severial times.

Now, Bi Luo define ans[i] as
the most value can Bi Luo gets if Bi Luo starts at node i.

Bi Luo is also an excited boy, now he wants to know every ans[i],
can you help him?

Input

First line is a positive integer T(T≤104) ,
represents there are T test
cases.

Four each test:

The first line contain an integer N(N≤105).

The next line contains N integers V[i],
which means the treasure’s value of node i(1≤V[i]≤104).

For the next N?1 lines,
each contains three integers u,v,c ,
which means node u and
node v are
connected by an edge, it‘s cost is c(1≤c≤104).

You can assume that the sum of N will
not exceed 106.

Output

For the i-th test case , first output Case #i: in a single line , then output N lines
, for the i-th line , output ans[i] in
a single line.

Sample Input

1
5
4 1 7 7 7
1 2 6
1 3 1
2 4 8
3 5 2

Sample Output

Case #1:
15
10
14
9
15

Author

UESTC

Source

2016中国大学生程序设计竞赛
- 网络选拔赛

题意:说给一棵树,点和边都有权值,经过一点可以加上该点的权值但最多只加一次,经过边会减去该边权值,问从各个点分别出发最多能获得多少权值。

分析:两个DFS分别在O(n)处理出两种信息,各个结点往其为根的子树走的信息各个结点往父亲走的信息,各个结点就能在O(1)合并这两个信息分别得出各个结点的最终信息。。

参考大神博客:http://www.cnblogs.com/WABoss/p/5771931.html

#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;
const double eps = 1e-6;
const double pi = acos(-1.0);
const int INF = 1e9;
const int MOD = 1e9+7;
#define ll long long
#define CL(a,b) memset(a,b,sizeof(a))
#define lson (i<<1)
#define rson ((i<<1)|1)
#define N 100010
int gcd(int a,int b){return b?gcd(b,a%b):a;}

struct node
{
    int v,c,next;
}e[N<<1];
int tot,head[N];

void add(int u, int v, int c)
{
    e[tot].v = v;
    e[tot].c = c;
    e[tot].next = head[u];
    head[u] = tot++;
}

int val[N];
int d_down[2][N],d_up[2][N];
///dp_down[0/1][u]:u结点往其为根的子树走,并且不走回来/走回来,能得到的最大权值
///dp_up[0/1][u]:u结点往其父亲向上走,并且不走回来/走回来,能得到的最大权值

void dfs1(int u, int fa)
{
    d_down[0][u] = d_down[1][u] = val[u];
    for(int i=head[u]; i!=-1; i=e[i].next)
    {
        int v = e[i].v;
        if(v == fa) continue;
        dfs1(v, u);
        if(d_down[0][v]-2*e[i].c>0)
            d_down[0][u] += d_down[0][v]-2*e[i].c;
    }
    int mx = 0;
    for(int i=head[u]; i!=-1; i=e[i].next)
    {
        int v = e[i].v;
        if(v == fa) continue;
        if(d_down[0][v]-2*e[i].c>0)
            mx = max(mx, (d_down[1][v]-e[i].c)-(d_down[0][v]-2*e[i].c));
        else mx = max(mx, d_down[1][v]-e[i].c);
    }
    d_down[1][u] = d_down[0][u] + mx;
}

void dfs2(int u, int fa)
{
    int mx1=0,mx2=0,tmp;
    for(int i=head[u]; i!=-1; i=e[i].next)
    {
        int v = e[i].v;
        if(v == fa) continue;
        if(d_down[0][v]-2*e[i].c>0)
            tmp=(d_down[1][v]-e[i].c)-(d_down[0][v]-2*e[i].c);
        else tmp=d_down[1][v]-e[i].c;

        if(mx1<tmp) mx2=mx1, mx1=tmp;
        else if(mx2<tmp) mx2=tmp;
    }

    for(int i=head[u]; i!=-1; i=e[i].next)
    {
        int v = e[i].v;
        if(v == fa) continue;
        int tmp2;
        if(d_down[0][v]-2*e[i].c>0)
            tmp2=d_down[0][u]-(d_down[0][v]-2*e[i].c);
        else tmp2=d_down[0][u];

        int mx=max(d_up[0][u]-2*e[i].c, tmp2-2*e[i].c);
        mx = max(mx, d_up[0][u]+tmp2-2*e[i].c-val[u]);
        d_up[0][v] = val[v]+max(0, mx);

        if(d_down[0][v]-2*e[i].c>0)
        {
            if(mx1==(d_down[1][v]-e[i].c)-(d_down[0][v]-2*e[i].c))
                tmp = d_down[1][u]-(d_down[1][v]-e[i].c)+mx2;
            else tmp = d_down[1][u]-(d_down[0][v]-2*e[i].c);
        }
        else if(d_down[1][v]-e[i].c>0)
        {
            if(mx1==d_down[1][v]-e[i].c)
                tmp = d_down[1][u]-(d_down[1][v]-e[i].c)+mx2;
            else tmp = d_down[1][u];
        }
        else tmp = d_down[1][u];
        mx = max(d_up[1][u]-e[i].c, tmp-e[i].c);
        mx = max(mx, max(d_up[0][u]+tmp-e[i].c-val[u], d_up[1][u]+tmp2-e[i].c-val[u]));
        d_up[1][v] = val[v]+max(0, mx);
        dfs2(v, u);
    }
}

int main()
{
    int T;
    scanf("%d",&T);
    for(int cas=1; cas<=T; cas++)
    {
        tot = 0;
        CL(head, -1);
        int n;
        scanf("%d",&n);
        for(int i=1; i<=n; i++)
            scanf("%d",val+i);
        int a,b,c;
        for(int i=1; i<n; i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            add(a, b, c);
            add(b, a, c);
        }
        dfs1(1, 1);
        d_up[0][1] = d_up[1][1] = val[1];
        dfs2(1, 1);
        printf("Case #%d:\n",cas);
        for(int i=1; i<=n; i++)
        {
            printf("%d\n",max(d_up[1][i]+d_down[0][i], d_up[0][i]+d_down[1][i])-val[i]);
        }
    }
    return 0;
}
时间: 2024-10-25 06:24:15

hdu5834 Magic boy Bi Luo with his excited tree(树形dp)的相关文章

&lt;hdu5834 Magic boy Bi Luo with his excited tree&gt; (树形DP)

题意:一棵树有点权和边权 从每个点出发 走过一条边要花费边权同时可以获得点权 边走几次就算几次花费 点权最多算一次 问每个点能获得的最大价值 题解:好吧 这才叫树形DP入门题 dp[i][0]表示从i节点的儿子中走又回到i的最大值 dp[i][1]表示不回到i的最大值 dp[i][2]表示不回到i的次大值 同时需要记录不回到i最大值的方向id[x] 很显然 第一遍dfs可以预处理每个节点往下的值 然后关键的就是每个节点从父亲这个方向的值怎么处理 有个很显然的结论就是 不回来是肯定比回来更优的 所

hdu 5834 Magic boy Bi Luo with his excited tree 树形dp+转移

Magic boy Bi Luo with his excited tree Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 1058    Accepted Submission(s): 308 Problem Description Bi Luo is a magic boy, he also has a migic tree,

Magic boy Bi Luo with his excited tree (树形dp)

Bi Luo is a magic boy, he also has a migic tree, the tree has NN nodes , in each node , there is a treasure, it's value is V[i]V[i], and for each edge, there is a cost C[i]C[i], which means every time you pass the edge ii , you need to pay C[i]C[i].

HDU 5834 Magic boy Bi Luo with his excited tree (树形DP)

题意:给定一棵树,每个点有个权值,每条边有权值,每经过边都会消耗相应的权值,但是点的权值只能获得一次,问你从 i 点出发能获得的最大权值是多少. 析:树形DP,就是太麻烦了,两次dfs,维护一共6个值分别是,从 i 出发的最大值并且返回 i, 从 i 出发的最大值并且不返回,从 i 出发的次大值并且不返回,从 i 出发的最大值的子树结点并且不返回,从 i 向父结点出发的最大值并且不返回,从 i 向父结点出发的最大值并且返回. 第一次dfs就能求出前四个,第二个dfs维护后面两个. 答案就是  m

树形DP CCPC网络赛 HDU5834 Magic boy Bi Luo with his excited tree

1 // 树形DP CCPC网络赛 HDU5834 Magic boy Bi Luo with his excited tree 2 // 题意:n个点的树,每个节点有权值为正,只能用一次,每条边有负权,可以走多次,问从每个点出发的最大获益 3 // 思路: 4 // dp[i]: 从i点出发回到i点的最大值 5 // d[i][0] 从i点出发不回来的最大值 6 // d[i][1] 从i点出发取最大值的下一个点 7 // d[i][2] 从i点出发取次大值 8 // dfs1处理出这四个 9

hdu5834 Magic boy Bi Luo with his excited tree 【树形dp】

题目链接 hdu5834 题解 思路很粗犷,实现很难受 设\(f[i][0|1]\)表示向子树走回来或不回来的最大收益 设\(g[i][0|1]\)表示向父亲走走回来或不回来的最大收益 再设\(h[i]\)为\(f[i][0]\)的次优收益 对于\(f[i][1]\),贪心选择所有\(f[v][1] - 2 * w \ge 0\)的子树即可 对于\(f[i][0]\),贪心选择所有没有被选的子树的\(f[v][0] - w \le 0\)的最大值 或者 被选子树\(f[v][1] - 2 * w

【HDOJ 5834】Magic boy Bi Luo with his excited tree(树型DP)

[HDOJ 5834]Magic boy Bi Luo with his excited tree(树型DP) Magic boy Bi Luo with his excited tree Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Problem Description Bi Luo is a magic boy, he also has a migic tree,

HDU 5834 Magic boy Bi Luo with his excited tree

题目:Magic boy Bi Luo with his excited tree 链接:http://acm.hdu.edu.cn/showproblem.php?pid=5834 题意:给一棵树,在树的每个结点可以收获一定的积分,每一条边会消耗一定的积分,每个结点积分取一次便完,但每次路过一条边,都会消耗积分,问从每一个结点出发,最多能捞多少积分.N范围10万,样例数1万. 思路: 不难的一道题,但细节较多,容易出错. 树形DP. 从i 点出发,大致可以分为向上 和 向下两种,先考虑向下的情

2016中国大学生程序设计竞赛 - 网络选拔赛 C. Magic boy Bi Luo with his excited tree

Magic boy Bi Luo with his excited tree Problem Description Bi Luo is a magic boy, he also has a migic tree, the tree has N nodes , in each node , there is a treasure, it's value is V[i], and for each edge, there is a cost C[i], which means every time