备注:一个结点,也可以称作一条链
题意:
思路:
- 将无根树转换为有根树,任意结点为根
- 在有根树上,设fir[ u ]为在结点u这颗子树上,包含结点u的权值和最大的子链。
- 同样地,设sec[ u ]为在结点u这颗子树上,包含结点u的权值和第二大的子链。
- 可以得到dp方程:
注意:
- ans初始化为负无穷,结点权值是有赋值的嘛
- ans = max(ans, val[ u ])放在跑儿子结点循环的外面,否则,如果结点个数为1,那么输出-INF,显然错了
END
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
inline int read()
{
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') { if(c == '-') f = -f; c = getchar(); }
while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
return x * f;
}
const int maxN = 100005;
int n, val[maxN];
struct EDGE{
int adj, to;
EDGE(int a = -1, int b = 0): adj(a),to(b){}
}edge[maxN << 1];
int head[maxN], cnt;
void add_edge(int u, int v)
{
edge[cnt] = EDGE(head[u], v);
head[u] = cnt ++ ;
}
void init()
{
memset(head, -1, sizeof(head));
cnt = 0;
}
ll fir[maxN], sec[maxN];
ll ans = ll(-INF);
void dfs(int u, int fa)
{
fir[u] = sec[u] = (ll)val[u];
ans = max(ans, (ll)val[u]);
for(int i = head[u]; ~i; i = edge[i].adj)
{
int v = edge[i].to;
if(v == fa) continue;
dfs(v, u);
if(fir[u] < fir[v] + (ll)val[u])
{
sec[u] = fir[u];
fir[u] = fir[v] + (ll)val[u];
}
else if(sec[u] < fir[v] + (ll)val[u])
sec[u] = fir[v] + (ll)val[u];
ans = max(ans, max(fir[u], fir[u] + sec[u] - (ll)val[u]));
}
}
int main()
{
init();
n = read();
for(int i = 1; i <= n; ++ i )
val[i] = read();
for(int i = 1; i < n; ++ i )
{
int u, v;
u = read(); v = read();
add_edge(u, v);
add_edge(v, u);
}
dfs(1, 0);
printf("%lld\n", ans);
return 0;
}