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