[题解]GYM 103328B Apple Tree

题意

给定一个 \(n\) 个节点的树,树上的每一个节点都有一个点权,每一条边都有一条边权。

现在你可以在树上任意选定一个起点出发,经过一些节点后返回该节点。

求此过程中的最大价值。(其中,价值为点权之和减去边权之和)

思路

树形 DP,定义 \(dp_i\) 表示以 \(i\) 为起点所能得到的最大价值。

那么,根据题目不难得出状态转移方程:\(dp_i = dp_j - 2 \times w_{i \to j} + a_i\)

由此,现在的难点就是如何确定起点。

因为树本身就是一个无向图,那么,对于两个点 \(u,v\),从 \(u\)\(v\) 的价值与从 \(v\)\(u\) 的价值相同。

因此,\(dp_i\) 的值与起点无关。

Code

#include <bits/stdc++.h>  
#define int long long  
#define re register  
  
using namespace std;  
  
const int N = 1e6 + 10,M = 2e6 + 10;  
int n,ans;  
int dp[N];  
int idx,arr[N],h[N],ne[M],e[M],w[M];  
  
inline int read(){  
    int r = 0,w = 1;  
    char c = getchar();  
    while (c < '0' || c > '9'){  
        if (c == '-') w = -1;  
        c = getchar();  
    }  
    while (c >= '0' && c <= '9'){  
        r = (r << 3) + (r << 1) + (c ^ 48);  
        c = getchar();  
    }  
    return r * w;  
}  
  
inline void add(int a,int b,int c){  
    ne[idx] = h[a];  
    e[idx] = b;  
    w[idx] = c;  
    h[a] = idx++;  
}  
  
inline void dfs(int u,int fa){  
    dp[u] = arr[u];  
    for (re int i = h[u];~i;i = ne[i]){  
        int j = e[i];  
        if (j == fa) continue;  
        dfs(j,u);  
        dp[u] = max(dp[u],dp[u] + dp[j] - 2 * w[i]);  
    }  
}  
  
signed main(){  
    memset(h,-1,sizeof(h));  
    n = read();  
    for (re int i = 1;i <= n;i++) arr[i] = read();  
    for (re int i = 1;i < n;i++){  
        int a,b,c;  
        a = read();  
        b = read();  
        c = read();  
        add(a,b,c);  
        add(b,a,c);  
    }  
    dfs(1,-1);  
    for (re int i = 1;i <= n;i++) ans = max(ans,dp[i]);  
    printf("%lld",ans);  
    return 0;  
}  
posted @ 2024-06-26 12:34  WBIKPS  阅读(14)  评论(0)    收藏  举报