1. 程式人生 > 其它 >2019 ICPC xuzhou M - Kill the tree(樹的重心)

2019 ICPC xuzhou M - Kill the tree(樹的重心)

題目連結
題意:
一顆以結點\(1\)為根結點的樹,求以每個結點\(i\)為根結點的樹的重心。

思路:
樹的重心的性質:
\(1\).把兩棵樹通過一條邊相連,新的樹的重心在原來兩棵樹重心的連線上。
(在兩顆樹的重心到根結點的路徑上)
\(2\).一棵樹最多有兩個重心,且相鄰。

每次合併兩顆樹,則新的樹的重心一定在兩顆樹的重心到當前根結點的路徑上。
新合併的樹的大小為\(sz[root]\)\(sz[i]\)表示以結點\(i\)為根結點為樹的大小,\(a、b\)為兩個樹的重心。
從兩顆樹的重心分別向當前根結點轉移,向上轉移一條邊,增加了\(sz[a]\),減少了\(sz[root]-sz[a]\)

。若\(sz[a] < sz[root] - sz[a]\),則向上更優,新的重心一定在上面。
最後注意特判以\(i\)為根結點的樹是否有兩個重心。

code:

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <cmath>
#include <map>
#include <set>
#include <unordered_map>

#define fi first
#define se second
#define pb push_back
// #define endl "\n"
#define debug(x) cout << #x << ":" << x << endl;
#define bug cout << "********" << endl;
#define all(x) x.begin(), x.end()
#define lowbit(x) x & -x
#define fin(x) freopen(x, "r", stdin)
#define fout(x) freopen(x, "w", stdout)
#define ull unsigned long long
#define ll long long

const double eps = 1e-5;
const int inf = INT32_MAX;
const ll INF = INT64_MAX;
const double pi = acos(-1.0);
const int mod = 998244353;
const int maxn = 2e5 + 10;

using namespace std;

vector<int> e[maxn];
int dep[maxn], zson[maxn];
int n, sz[maxn], fa[maxn]; 

void getson(int u, int a, int b){
    while(a != u && sz[a] < sz[u] - sz[a])a = fa[a];
    while(b != u && sz[b] < sz[u] - sz[b])b = fa[b];
    if(dep[a] > dep[b])zson[u] = a;
    else zson[u] = b;
}

void dfs(int u, int pre){
    sz[u] = 1, fa[u] = pre;
    zson[u] = u, dep[u] = dep[pre] + 1;

    for(int v : e[u]){
        if(v == pre)continue;
        dfs(v, u);
        sz[u] += sz[v];
        getson(u, zson[u], zson[v]);
    }
}

int main(){
    scanf("%d", &n);
    for(int i = 1; i < n; i ++){
        int a, b;
        scanf("%d%d", &a, &b);
        e[a].pb(b), e[b].pb(a);
    }

    dfs(1, 0);
    for(int i = 1; i <= n; i ++){
        if(sz[zson[i]] == (sz[i] - sz[zson[i]])){
            printf("%d %d\n", min(zson[i], fa[zson[i]]), max(zson[i], fa[zson[i]]));
        }
        else printf("%d\n", zson[i]);
    }
    return 0;
}