树的重心

概念

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

性质

树的重⼼如果不唯⼀,则⾄多有两个,且这两个重⼼相邻。
• 以树的重⼼为根时,所有⼦树的⼤⼩都不超过整棵树⼤⼩的⼀半。
• 树中所有点到某个点的距离和中,到重⼼的距离和是最⼩的;如果有两个重⼼,那么到它们的距离
和⼀样。
◦ 推论⼀:即使边权不为1 ,只要没有负边权,不影响各点到重⼼的距离和最⼩;
◦ 推论⼆:即使边权和点权都不为1 ,只要没有负边权,不影响各点到重⼼的距离和最⼩。

实现

#include <iostream>
#include <vector>
using namespace std;
const int N = 5e4 + 10;
int n;
vector<int> edges[N];
int f[N]; // f[x] 表⽰:以 x 为根的⼦树的⼤⼩ 
int r1, r2, ret = N;
void dfs(int x, int fa){
    f[x] = 1;
    int m = 0; // 把 x 删除之后,所有⼦树的最⼤值 
    for(auto y : edges[x]){
        if(y == fa) continue;
        dfs(y, x);
        m = max(m, f[y]);
        f[x] += f[y];
    }
    m = max(m, n - f[x]);
    if(m < ret){
        r1 = x, r2 = 0;
        ret = m;
    }
    else if(m == ret){
        r2 = x;
    }
}
int main(){
    cin >> n;
    for(int i = 1; i < n; i++){
        int a, b; cin >> a >> b;
        edges[a].push_back(b);
        edges[b].push_back(a);
    }
    dfs(1, 0);
    if(r1 > r2) swap(r1, r2);
    if(r1 && r2) cout << r1 << " " << r2 << endl;
    else cout << r2 << endl;
    return 0;
}

posted @ 2025-08-29 15:43  xdhking  阅读(17)  评论(0)    收藏  举报