树的重心的概念

如果在树中选择某个节点并删除,这棵树将分为若干棵子树,统计子树节点数并记录最大值。取遍树上所有节点,使此最大值取到最小的节点被称为整个树的重心。

说白了就是删去一个点,使这一颗树碎成的块块大小最平均的那一个点,就是重心。

树的重心的代码

我们只需要把每一个子树的大小都处理出来,在该节点的父亲方向的点可以用总量减去所有的儿子方向的子树。处理出所有子树的最大值,按照定义模拟即可。

值得注意的是,一个树可以有多个重心,但是他们一定相邻。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include<bits/stdc++.h>
using namespace std;

int n;
vector<int >e[10010];

int size[10010];
int g[10010];

void Input(){
scanf("%d", &n);
int u, v;
for(int i=1; i<n; i++){
scanf("%d%d", &u, &v);
e[u].push_back(v);
e[v].push_back(u);
}
}

void Dfs(int u, int fa){
size[u]=1;
for(auto &p:e[u]){
if(p==fa) continue;
Dfs(p, u);
size[u]+=size[p];
g[u]=max(g[u], size[p]);
}
g[u]=max(g[u], n-size[u]);
}

void Work(){
Dfs(1, 0);
int x=1;
for(int i=1; i<=n; i++){
if(g[i]<g[x]) x=i;
}
set<int >st;
for(int i=1; i<=n; i++){
if(g[i]==g[x]){
st.insert(i);
}
}
for(auto &p:st){
printf("%d ", p);
}
}

int main(){
Input();
Work();
return 0;
}

树的重心经典例题