題解 HDU5834 【Magic boy Bi Luo with his excited tree】
阿新 • • 發佈:2021-08-14
前置芝士:換根 dp
首先考慮不換根的做法,設 \(dp1_u\) 表示在 \(u\) 的子樹裡走且需要回到 \(u\) 所能獲得的最大收益,\(dp2_u\) 表示在 \(u\) 的子樹裡走且不需要回到 \(u\) 所能獲得的最大收益。
顯然,\(dp1_u = V_u + \displaystyle\sum_{u \to^w v} \max(dp1_v - 2w, 0)\)。
程式碼:
#include <stdio.h> typedef long long ll; typedef struct { int nxt; int end; int dis; } Edge; int cnt; int head[100007], max_val[100007], second_max_val[100007], v[100007], dp1[100007], dp2[100007], max_val_son[100007], second_max_val_son[100007], ans[100007]; Edge edge[200007]; inline void init(int n){ cnt = 0; for (int i = 1; i <= n; i++){ head[i] = max_val[i] = second_max_val[i] = 0; } } inline int read(){ int ans = 0; char ch = getchar(); while (ch < '0' || ch > '9'){ ch = getchar(); } while (ch >= '0' && ch <= '9'){ ans = ans * 10 + (ch ^ 48); ch = getchar(); } return ans; } inline void add_edge(int start, int end, int dis){ cnt++; edge[cnt].nxt = head[start]; head[start] = cnt; edge[cnt].end = end; edge[cnt].dis = dis; } inline int max(int a, int b){ return a > b ? a : b; } inline void update(int u, int v, int val){ if (max_val[u] < val){ second_max_val[u] = max_val[u]; second_max_val_son[u] = max_val_son[u]; max_val[u] = val; max_val_son[u] = v; } else if (second_max_val[u] < val){ second_max_val[u] = val; second_max_val_son[u] = v; } } void dfs1(int u, int father){ dp1[u] = v[u]; for (int i = head[u]; i != 0; i = edge[i].nxt){ int x = edge[i].end; if (x != father){ int t; dfs1(x, u); t = max(dp1[x] - edge[i].dis * 2, 0); dp1[u] += t; update(u, x, max(dp2[x] - edge[i].dis, 0) - t); } } dp2[u] = dp1[u] + max_val[u]; } void dfs2(int u, int father){ for (int i = head[u]; i != 0; i = edge[i].nxt){ int x = edge[i].end; if (x != father){ int t = max(dp1[x] - edge[i].dis * 2, 0), y = dp1[u] - t, z; if (max_val_son[u] == x){ z = dp2[u] + second_max_val[u] - max(dp2[x] - edge[i].dis, 0); } else { z = dp2[u] - t; } t = max(y - edge[i].dis * 2, 0); dp1[x] += t; ans[x] = dp2[x] + t - max_val[x]; update(x, u, max(z - edge[i].dis, 0) - t); ans[x] += max_val[x]; dp2[x] = ans[x]; dfs2(x, u); } } } inline void write(int n){ if (n >= 10) write(n / 10); putchar(n % 10 + '0'); } int main(){ int t = read(); for (int i = 1; i <= t; i++){ int n = read(); init(n); for (int j = 1; j <= n; j++){ v[j] = read(); } for (int j = 1; j < n; j++){ int u = read(), v = read(), c = read(); add_edge(u, v, c); add_edge(v, u, c); } dfs1(1, 0); dfs2(1, 0); ans[1] = dp2[1]; printf("Case #"); write(i); printf(":\n"); for (int j = 1; j <= n; j++){ write(ans[j]); putchar('\n'); } } return 0; }