刚学树形dp表示WA哭了,调了半天才调出来。

树的直径:
对于一颗n个结点的无根树,找到一条最长路径,也就是找到两个点,让他们的距离最远。
学习树形dp之前,有一个操作,就是通过第一次dfs找到一个最深叶子结点,再通过这个点为根,去找另一个最深的叶子结点,就完成了最长链的操作,这个方法虽然简单,但是不够酷。
学习了树形dp,我们有一个操作,就是对于任意一个点为根(无向图以谁为根都无所谓),找到最大的子树,再找到第二大的子树,把他们加起来,再找到自己就可以了,这个就通过动态规划去逐步下放完成。

这题跟树的直径问题有点像,但是它是带权值的,略微有些不同。
root点的ans应该是该点的
dp[root]+dp[son]
dp[root]初始值为val[root],或者由其他儿子更新而来,这样就可以求出整一条链。
也就是自己这个点,连到最长的一个儿子,就是dp[root]的值,再通过另一个很大的儿子,去找到另一个叶子结点
然后更新root点的dp值
dp[root]=dp[son]+val[root]

本题要注意的点:
1.OI/ACM十年终是空,不开long long见祖宗
2.叶子结点同样要记得更新答案,不然通过90%的样例

以下是代码:

#include <bits/stdc++.h>
using namespace std;
const int N=100100;
#define ll long long
int n;
ll val[N];//记录每一个结点的权值
ll dp[N];
vector <int> G[N];
ll ans=-1e12;
void dfs(int root,int pre)
{
    ans=max(ans,val[root]);
    dp[root]=val[root];
    for(int i=0;i<G[root].size();i++)
    {
        int to=G[root][i];
        if(to==pre) continue;
        dfs(to,root);
        ans=max(ans,dp[root]+dp[to]);
        dp[root]=max(dp[root],dp[to]+val[root]);
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%lld",&val[i]);
    for(int i=1;i<n;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs(1,0);
    printf("%lld\n",ans);
}