2019 ICPC xuzhou M - Kill the tree(樹的重心)
阿新 • • 發佈:2021-10-30
題目連結
題意:
一顆以結點\(1\)為根結點的樹,求以每個結點\(i\)為根結點的樹的重心。
思路:
樹的重心的性質:
\(1\).把兩棵樹通過一條邊相連,新的樹的重心在原來兩棵樹重心的連線上。
(在兩顆樹的重心到根結點的路徑上)
\(2\).一棵樹最多有兩個重心,且相鄰。
每次合併兩顆樹,則新的樹的重心一定在兩顆樹的重心到當前根結點的路徑上。
新合併的樹的大小為\(sz[root]\),\(sz[i]\)表示以結點\(i\)為根結點為樹的大小,\(a、b\)為兩個樹的重心。
從兩顆樹的重心分別向當前根結點轉移,向上轉移一條邊,增加了\(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; }