算法总结—树的中心1
树的中心定义
一棵树,当点 \(u\) 为根时,树的深度最小,\(u\) 就是树的中心。
关于树的中心的性质
-
树的中心最多有两个。如果有两个,一定相邻。
-
所有点到它最远的点的路径中一定有树的直径。
-
当书的中心为根时,以根为起点的最长链与次长链构成树的直径。
-
树的中心一定在树的直径上。
树的中心的求法
首先想到维护最长链 \(dis_{1,u}\),最长链最短时就是树的中心。但是最长链只在子树内,子树外的点没有考虑进去,所以还得维护子树外的最长链 \(up_u\)。
\(up_v\) 可以继承 \(up_{fa}\),\(v\) 为 \(fa\) 的一个孩子。但是要避免一种情况:最长链就在 \(u\) 的子树内(\(dis_{1,v}=dis_{1,fa}+w\)),遇到这种情况时,\(up_v\) 就与次长链有关了,所以在之前还需要求出次长链 \(dis_{2,u}\)。
【模板】树的中心
求出 \(dis_{1,i},dis_{2,i},up_i\) 后,当 \(\max\{dis_{1,i},up_i\}\) 最小时,\(i\) 就是树的中心。
代码
#include<bits/stdc++.h>
using namespace std;
int dis[5][100005];
int up[100005];
struct edge{
int v,w;
};
vector<edge>G[100005];
void dfs_down(int u,int father){
for(auto i:G[u]){
int v=i.v;
int w=i.w;
if(v==father){
continue;
}
dfs_down(v,u);
if(dis[1][v]+w>dis[1][u]){
dis[2][u]=dis[1][u];
dis[1][u]=dis[1][v]+w;
}else if(dis[1][v]+w>dis[2][u]){
dis[2][u]=dis[1][v]+w;
}
}
return;
}
void dfs_up(int u,int father){
for(auto i:G[u]){
int v=i.v;
int w=i.w;
if(v==father){
continue;
}
up[v]=up[u]+w;
if(dis[1][v]+w==dis[1][u]){
up[v]=max(up[v],dis[2][u]+w);
}else{
up[v]=max(up[v],dis[1][u]+w);
}
dfs_up(v,u);
}
return;
}
int main(){
int n;
cin>>n;
for(int i=1;i<n;i++){
int u,v,w;
cin>>u>>v>>w;
G[u].push_back({v,w});
G[v].push_back({u,w});
}
dfs_down(1,0);
dfs_up(1,0);
int Min=1e9;
for(int i=1;i<=n;i++){
Min=min(Min,max(dis[1][i],up[i]));
}
for(int i=1;i<=n;i++){
if(max(dis[1][i],up[i])==Min){
cout<<i<<"\n";
}
}
return 0;
}

浙公网安备 33010602011771号