求树上最长链(或者说树的直径、树上距离最远的两点距离,树中所有最短路径距离的最大值qwq)的模板题,网上讲解很多,注意点权有负数即可

参考资料1(by ROCKYONE)

参考资料2(by forever_dreams)

1.树形DP(可以有效处理负边权)
2.两次dfs或bfs(无法处理负边权)

树的直径 = (在某个节点的子树中以它为端点的) 最长链 + 次长链
(连接起来可以得到一条更长的链,当然有时没有次长链,仅是一条最长链)

mx表示以i为根的子树中,i到叶子结点距离(不包括p[i])的最大值,即上面说的最长链
mx2表示以i为根的子树中,i到叶子结点距离(不包括p[i])的次大值,即上面说的次长链

ans=max(ans,max(mx+p[i],mx+mx2+p[i]))//p是点权

由于mx2>=0,所以可以直接写为ans=max(ans,mx+mx2+p[x])

#include<cstdio>
using namespace std;
#define max(a,b) (a>b ? a:b)
#define ll long long
const int N=100005;
const ll inf=-0x3f3f3f3f3f3f3f3f;
struct edge{
    int v,h;
}e[N<<1];
int n,p[N],head[N],tot;
ll ans=inf;//注意点权有负数
inline void add(int u,int v){
    e[++tot]=(edge){
        v,head[u]
    },head[u]=tot;
}
ll dfs(int x,int fa){
    ll tmp,mx=0,mx2=0;//最长链与次长链初始化为0,如果链为负数我们不如不要
    for (int i=head[x],v;i;i=e[i].h)
    if ((v=e[i].v)^fa){
        tmp=dfs(v,x);
        if (tmp>mx) mx2=mx,mx=tmp;
        else if (tmp>mx2) mx2=tmp;
    }
    ans=max(ans,mx+mx2+p[x]);
    return mx+p[x];//最长链可以继续上传更新答案,但最长链和次长链连接起来不能上传
}
int main(){
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",&p[i]);
    for (int i=1,x,y;i<n;i++)
     scanf("%d %d",&x,&y),add(x,y),add(y,x);
    dfs(1,-1);
    printf("%lld",ans);
}