传送门:树的中心
思路:第一遍向下深搜遍历,用子节点更新父节点,造出每一个向下的最大距离和次大距离,同时标记叶节点。
第二遍用父节点更新子节点,更新子节点向上的最大距离,相当于找父节点的其他方向向下的最大距离或向上的距离里面最大的一个。
如图在更新2的向上最大距离时,需要找到节点1向上0的方向或是向下3的方向里面距离最大的一个,然后加上1到2的距离作为2向上的最大距离
代码:
#include<iostream>
#include<cstring>
#include <cmath>
#include<algorithm>
#include <vector>
using namespace std;
const int N=1e4+7;
int n;
int ans;
bool st[N];
int d1[N],d2[N],p1[N],p2[N],up[N];
int idx,e[N*2],h[N],ne[N*2],w[2*N];
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int dfs_d(int root,int father)//向下搜索最长路径和次长路径
{
d1[root]=d2[root]=-0x3f3f3f3f;
for(int i=h[root];i!=-1;i=ne[i])
{
int j=e[i];
if(j==father)
continue;
int d= dfs_d(j,root)+w[i];
if (d >= d1[root])
{
d2[root] = d1[root], d1[root] = d;
p1[root]=j;
}
else if (d > d2[root])
{
d2[root] = d;
}
}
if(d1[root]==-0x3f3f3f3f)
{
d1[root]=d2[root]=0;
st[root]=true;
}
return d1[root];
}
//向上找最长路径,上一个点也有两个方向,要么向下要么向上,向下时要检查方向是否和来源相同,
//相同就次大和最大的另一个
void dfs_u(int root ,int father)
{
for(int i=h[root];i!=-1;i=ne[i])
{
int j=e[i];
if(j==father) continue;
if(p1[root]==j) up[j]=max(up[root],d2[root])+w[i];
else up[j]=max(up[root],d1[root])+w[i];
dfs_u(j,root);
}
}
int main()
{
cin>>n;
memset(h,-1,sizeof h);
for(int i=1;i<=n-1;i++)
{
int a,b,c;
cin>>a>>b>>c;
add(a,b,c);
add(b,a,c);
}
dfs_d(1,-1);
dfs_u(1,-1);
int res=d1[1];
for(int i=2;i<=n;i++)//遍历每一个点,叶节点就只有向上的选择
if(st[i])
res=min(res,up[i]);
else
res=min(res,max(d1[i],up[i]));
cout<<res;
return 0;
}