1. 程式人生 > 其它 >題解 HDU5834 【Magic boy Bi Luo with his excited tree】

題解 HDU5834 【Magic boy Bi Luo with his excited tree】

前置芝士:換根 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;
}