https://lucien.ink
https://codeforces.com/contest/1084/problem/D
给你一棵树,数上的每个点都有一个正权值,每条边都有一个负权值,让你在树中找一条简单路径,使得权值和最大。
我们定义 f i f_i fi 为从以节点 i i i 为根的子树中出发,到达节点 i i i 时的最大权值和,转移方程为:
f u = m a x { f v − c o s t u , v + w u } f_u = max\{f_v - cost_{u, v} + w_u\} fu=max{fv−costu,v+wu}
这样处理的是竖着的路径,其中 v v v 是 u u u 的每一个儿子。穿过节点 i i i 的横向路径的最大值为:
( f v 1 − c o s t u , v 1 ) 最 大 值 + ( f v 2 − c o s t u , v 2 ) 次 大 值 + w u ({f_{v_1} - cost_{u, v_1}})_{最大值} + ({f_{v_2} - cost_{u, v_2}})_{次大值} + w_u (fv1−costu,v1)最大值+(fv2−costu,v2)次大值+wu
答案在所有 f i f_i fi 与上述表达式中取最大值,复杂度为 O ( n ) O(n) O(n)。
https://pasteme.cn/2421
#include
const int maxn = int(3e5) + 7;
std::vector<std::pair<int, long long>> edge[maxn];
long long ans = 0, f[maxn];
int n, w[maxn];
void dfs(int u, int pre) {
f[u] = w[u];
long long max[2] = {0, 0};
for (auto cur : edge[u]) {
int v = cur.first;
long long cost = cur.second;
if (v != pre) {
dfs(v, u);
long long tmp = f[v] - cost;
if (tmp > max[0]) std::swap(max[0], tmp);
max[1] = std::max(max[1], tmp);
f[u] = std::max(f[u], f[v] - cost + w[u]);
}
}
ans = std::max({f[u], ans, max[0] + max[1] + w[u]});
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", w + i);
for (int i = 1, u, v, cost; i < n; i++) {
scanf("%d%d%d", &u, &v, &cost);
edge[u].emplace_back(v, cost);
edge[v].emplace_back(u, cost);
}
dfs(1, 1);
printf("%lld\n", ans);
return 0;
}