1. 程式人生 > 其它 >[模版]最大子樹和 題解

[模版]最大子樹和 題解

[模版]最大子樹和 題解

前置芝士

樹上DP

題目大意

給出一棵樹,上面有權值, 求這個數的子樹的最大權值和。

模板題,就是樹上DP。

可以想到只要這個樹的子樹的權值大於0就可以選擇,即加上這個權值。

所以這個DP的轉移方程是 \(f_i=\sum_{i=1}^nf_{a_i}[{f_{a_i}}>0]\)

其中 \(n\) 表示這個子樹大小,\(a_i\) 表示這個子樹的子節點。

#include <bits/stdc++.h>

using i64 = long long;

constexpr int N = 16010;
struct node {
	int dis, next;
} edge[N << 1];
int head[N + 1], siz;
inline void add(int from, int dis) {
	edge[++siz].dis = dis;
	edge[siz].next = head[from];
	head[from] = siz;
}
int f[N + 1];
int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(0), std::cout.tie(0);
	
	int n;	
	std::cin >> n;
	
	for (int i = 1; i <= n; i++) {
		std::cin >> f[i];
	}
	
	for (int i = 1; i < n; i++) {
		int u, v;
		std::cin >> u >> v;
		add(u, v); add(v, u);
	}
	int ans = -2147483647;
	
	std::function <void(int, int)> dfs = [&](int u, int fa) {
		for (int i = head[u]; i; i = edge[i].next) {
			int v = edge[i].dis;
			if (v != fa) {
				dfs(v, u);
				f[u] += (f[v] > 0 ? f[v] : 0);
			}
		}
		ans = std::max(ans, f[u]);
	};
	
	dfs(1, 0);
	std::cout << ans << std::endl;
	
	return 0;
}