树的重心
概念
对于一个树中,拥有最大子树节点数最小的节点即为树的重心
性质
对于树的重心,有如下性质
- 树的重心如果不唯一,则至多有两个,且这两个重心相邻
- 以树的重心为根时,所有子树的大小都不超过整棵树大小的一半
- 树中所有点到某个点的距离和中,到重心的距离和是最小的;如果有两个重心,那么到它们的距离和一样
- 把两棵树通过一条边相连得到一棵新的树,那么新的树的重心在连接原来两棵树的重心的路径上
- 在一棵树上添加或删除一个叶子,那么它的重心最多只移动一条边的距离
写法
对于树的重心定义,我们可以先从一号节点开始搜索树,对于每一个节点,枚举它往下搜索的最大子树$x$,同时把往下搜索的节点和(包含自己)用总结点数减去,即是上面节点所在子树的节点数$y$,再将$x$与$y$取大值,即是该结点所构成子树最大值
枚举每一个结点,最大值最小的结点即是树的重心
模板
题目大意
对于一个树,求距离所有其他结点总距离最小的结点
思路
由树的重心性质可知,该题实质上所求即为树的重心
代码
#include<bits/stdc++.h>
using namespace std;
int n,s[500010],top,cnt,f[500010],he[1000010],d[500010],ans;
struct node{
int v;
int nx;
}e[1000010];
void add(int x,int y){
e[++cnt].v=y,e[cnt].nx=he[x],he[x]=cnt;
}
void get(int x,int fa){
s[x]=1,f[x]=0;
for(int i=he[x];i;i=e[i].nx){
int v=e[i].v;
if(v==fa){
continue;
}
get(v,x);
s[x]+=s[v];
f[x]=max(f[x],s[v]);
}
f[x]=max(f[x],n-s[x]);
if(f[x]<f[top]||(f[x]==f[top]&&x<top))
top=x;
}
void dfs(int x,int fa){
for(int i=he[x];i;i=e[i].nx){
int v=e[i].v;
if(v==fa)continue;
d[v]=d[x]+1;
dfs(v,x);
}
}
int main(){
f[0]=INT_MAX;
cin>>n;
for(int i=1;i<=n-1;i++){
int x,y;
cin>>x>>y;
add(x,y);
add(y,x);
}
get(1,0);
dfs(top,0);
for(int i=1;i<=n;i++){
ans+=d[i];
}
return 0;
}
这里要注意,如果有两个重心,要求编号小的