树的重心
概念
在树中,必然存在一个或多个点,保证此点相连的结点数最多的连通块的结点数最小,我们把这个点叫做树的“重心”。
这边关键是把几个数组的含义理解好就差不多了。中间的建树自然不用说。dfs遍历跟LCA差不多滴,这个我会,很开心。
linkk是建树时用到的,son[i]存节点i所在的子树大小,f[i]存节点i将树分成的几个联通块中最大的一块的节点数。
#include<bits/stdc++.h>
using namespace std;
const int maxn=200010;
int n,xx,yy,temp,linkk[maxn],k,son[maxn],f[maxn],ans=2000000000;
struct atree
{
int y,next;
}
a[maxn];
inline int read()
{
int num=0,flag=1;
char c=getchar();
for (;c<'0'||c>'9';c=getchar())
if (c=='-') flag=-1;
for (;c>='0'&&c<='9';c=getchar())
num=(num<<3)+(num<<1)+c-48;
return num*flag;
}
void insertt(int ss,int ee)
{
a[++temp].y=ee;
a[temp].next=linkk[ss];
linkk[ss]=temp;
}
void dfs(int t,int father)
{
son[t]=1;//初始值
for (int i=linkk[t];i;i=a[i].next)
{
int k=a[i].y;
if (k==father) continue;
dfs(k,t);
son[t]+=son[k];//加上子树的节点数
f[t]=max(f[t],son[k]);//记录最大的联通块节点数
}
f[t]=max(f[t],n-son[t]);//计算剩余的一个联通块大小
ans=min(ans,f[t]);//更新重心
}
int main()
{
n=read();
for (int i=1;i<n;++i)
{
xx=read();
yy=read();
insertt(xx,yy);
insertt(yy,xx);
}
dfs(1,0);
for (int i=1;i<=n;++i)
if (f[i]==ans) printf("%d ",i);
return 0;
}