树的重心
树的重心也叫树的质心。
对于一棵树n个节点的无根树,找到一个点,使得把树变成以该点为根的有根树时,最大子树的结点数最小。换句话说,删除这个点后最大连通块(一定是树)的结点数最小。
性质
(1)树中所有点到某个点的距离和中,到重心的距离和是最小的,如果有两个距离和,他们的距离和一样。
(2)把两棵树通过一条边相连,新的树的重心在原来两棵树重心的连线上。
(3)一棵树添加或者删除一个节点,树的重心最多只移动一条边的位置。
(4)一棵树最多有两个重心,且相邻。
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
inline int read() /// 读入
{
char k=0;char ls;ls=getchar();for(;ls<'0'||ls>'9';k=ls,ls=getchar());
int x=0;for(;ls>='0'&&ls<='9';ls=getchar())x=x*10+ls-'0';
if(k=='-')x=0-x; return x;
}
int n;
int k;
int edge[100050];
int pre[100050];
int last[100050];
int g=0;
int sum[100050];
int maxj[100050];
int minn=INT_MAX;
void dfs(int d,int fa)
{
for(int i=last[d];i!=0;i=pre[i])
{
int z=edge[i];
if(z!=fa)
{
dfs(z,d);
}
}
maxj[d]=max(maxj[d],n-sum[d]-1); /// 最大后子树 前子树
minn=min(minn,maxj[d]);
sum[d]+=1; /// 加上当前点
sum[fa]+=sum[d]; /// 加上所有子树 父节点作为子树
maxj[fa]=max(sum[d],maxj[fa]); /// 最大后子树
return;
}
int m;
int main()
{
n=read();
m = read();
int a1,b1;
for(int i=0;i<m;++i)
{
a1=read(),b1=read();
edge[++g]=b1;
pre[g]=last[a1];
last[a1]=g;
edge[++g]=a1;
pre[g]=last[b1];
last[b1]=g;
}
dfs(a1,0);
for(int i=1;i<=n;++i)
if(maxj[i]==minn)
cout<<i<<" ";
cout<<endl;
return 0;
}