求树上最长链(或者说树的直径、树上距离最远的两点距离,树中所有最短路径距离的最大值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); }