树的中心
给定一棵树,树中包含 n 个结点(编号1~n)和 n−1 条无向边,每条边都有一个权值。
请你在树中找到一个点,使得该点到树中其他结点的最远距离最近。
输入格式
第一行包含整数 n。
接下来 n−1 行,每行包含三个整数 ai,bi,ci,表示点 ai 和 bi 之间存在一条权值为 ci 的边。
输出格式
输出一个整数,表示所求点到树中其他结点的最远距离。
数据范围
1≤n≤10000,
1≤ai,bi≤n,
−105≤ci≤105
输入样例:
5
2 1 1
3 2 1
4 3 1
5 1 1
输出样例:
2
题解:
这道题需要让我们求树的中心最大的最小,我们先把树当成一个圆,是不是只有处于圆心的时候我们能够保证距离最小。所以我们树的中心也是这样的道理。我们要找到一个点离最上面的根的最长距离和最下面的最长距离,然后取这两个小的一个值。所以我们需要进行两次树形DP。一次是向上一次是向下。对于我们叶子节点就只能向上。这里和上一题有点相似的地方是什么呢?上去的过程中当我们这个结点向下拥有的距离是我们以相同根的同层次的节点中向下距离里最大的。那么我们可以选择另外一个第二大的距离(因为要保证最大的最小),但是如果我们不是这个节点的话我们就只能去包含那个距离最大的节点(因为要保证最大)。
#include<bits/stdc++.h>
using namespace std;
const int N=2e4+7,inf=0x3f3f3f3f;
int ne[N],h[N],w[N],e[N],cnt,d1[N],d2[N],r1[N],r2[N],up[N];
bool lef[N];
void add(int a,int b,int c)
{
e[cnt]=b,w[cnt]=c,ne[cnt]=h[a],h[a]=cnt++;
}
int dfs_d(int u,int f)
{
d1[u]=d2[u]=-inf;
for(int i=h[u];i!=-1;i=ne[i]){
int j=e[i];
if(j==f) continue;
int d=dfs_d(j,u)+w[i];
if(d>=d1[u]){
d2[u]=d1[u]; d1[u]=d;
r2[u]=r1[u]; r1[u]=j;
}else if(d>=d2[u]) d2[u]=d,r2[u]=j;
}
if(d1[u]==-inf){
d1[u]=d2[u]=0;
lef[u]=1;
}
return d1[u];
}
int dfs_u(int u,int f)
{
for(int i=h[u];i!=-1;i=ne[i]){
int j=e[i];
if(j==f) continue;
if(r1[u]==j) up[j]=max(up[u],d2[u])+w[i];
else up[j]=max(up[u],d1[u])+w[i];
dfs_u(j,u);
}
}
int main()
{
int n; cin>>n;
memset(h,-1,sizeof h);
for(int i=1;i<n;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(lef[i]) res=min(res,up[i]);
else res=min(res,max(d1[i],up[i]));
}
cout<<res<<endl;
}