题意:给出一棵树,每个节点有一个权值,求出不相交的两条链的最大权值和。
思路:树形DP。
可以发现一棵树的两条链一共会出现以下七种情况,七种情况又可以进一步划分成四种情况
f[u][0] 表示以u为根的子树中最长的两条链之和
f[u][1] 表示以u为根的子树中最长的一条链
g[u] 表示以u为根的子树中从u到叶子节点加上另外一条链的最长长度
h[u] 表示以u为根的子树中儿子节点中f[son][1]的最大值
down[u] 表示从u到叶子节点的最长长度
然后在dfs的过程中进行递推即可。
#include<bits/stdc++.h>
#define eps 1e-6
#define LL long long
#define pii pair<int, int>
#define pb push_back
#define mp make_pair
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int MAXN = 100100;
//const int INF = 0x3f3f3f3f;
int n;
vector<int> G[MAXN];
int w[MAXN];
/*
*f[u][0] 表示以u为根的子树中最长的两条链之和
*f[u][1] 表示以u为根的子树中最长的一条链
*
*g[u] 表示以u为根的子树中从u到叶子节点加上另外一条链的最长长度
*h[u] 表示以u为根的子树中儿子节点中f[son][1]的最大值
*down[u] 表示从u到叶子节点的最长长度
*/
LL f[MAXN][2], g[MAXN], h[MAXN], down[MAXN];
void dfs(int cur, int fa) {
f[cur][0] = w[cur];
f[cur][1] = w[cur];
g[cur] = w[cur];
h[cur] = 0;
down[cur] = w[cur];
for (int i = 0; i < G[cur].size(); i++) {
int u = G[cur][i];
if (u == fa) continue;
dfs(u, cur);
//一共四种情况
f[cur][0] = max(f[cur][0], f[u][0]);
f[cur][0] = max(f[cur][0], f[cur][1]+f[u][1]);
f[cur][0] = max(f[cur][0], down[cur]+g[u]);
f[cur][0] = max(f[cur][0], g[cur]+down[u]);
//一共两种情况
f[cur][1] = max(f[cur][1], f[u][1]);
f[cur][1] = max(f[cur][1], down[cur]+down[u]);
g[cur] = max(g[cur], w[cur]+g[u]);
g[cur] = max(g[cur], down[cur]+f[u][1]);
g[cur] = max(g[cur], down[u]+w[cur]+h[cur]);
h[cur] = max(h[cur], f[u][1]);
down[cur] = max(down[cur], down[u]+w[cur]);
}
}
int main()
{
//freopen("input.txt", "r", stdin);
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &w[i]);
for (int i = 1; i < n; i++) {
int u, v;
scanf("%d%d", &u, &v);
G[u].pb(v);
G[v].pb(u);
}
dfs(1, 0);
printf("%I64d", f[1][0]);
return 0;
}