樹的重心的定義是,對樹中的某個點,以這個點為根,然後它會擁有若干棵子樹,取出最大的那棵子樹的size,然後在所有點中求最小的最大的子樹的size的點,這個點就是樹的重心。簡單來說就是找到某個點r,去掉r之後,每棵子樹是長得最平均的。樹的重心最多有2個(這時候重心其實是在這兩點之間的邊上),最少有1個。
由於所有的子樹是長得最平均的,而且樹的重心常規情況下都不是葉子,那麼一般都會有多棵子樹。其中最大的一棵子樹的節點數不會超過原樹規模的一半。否則,如果某個子樹超過了原樹規模的一半,那麼除去這棵子樹以外,當前節點和當前節點的其他子樹加起來的數量不夠原樹規模的一半,那麼這時候以這棵子樹的樹根代替當前節點會更好。(聽起來有點像換根dp的思路哈哈)
只找一次重心:
const int MAXN = 2e5 + 10;
int n;
vector<int> G[MAXN];
int center, center_max_siz;
int siz[MAXN];
void find_center (int u, int p) {
siz[u] = 1;
int max_siz = 0;
for (const int &v : G[u]) {
if (v == p) {
continue;
}
find_center (v, u);
siz[u] += siz[v];
cmax (max_siz, siz[v]);
}
cmax (max_siz, n - siz[u]);
if (center == 0 || max_siz < center_max_siz) {
center = u;
center_max_siz = max_siz;
}
}
void solve() {
RD (n);
for (int i = 1; i <= n; ++i) {
G[i].clear();
}
for (int i = 1; i <= n - 1; ++i) {
int u, v;
RD (u, v);
G[u].push_back (v);
G[v].push_back (u);
}
center = 0, center_max_siz = INF;
find_center (1, 0);
WT (center);
}
多次找重心,每次找到重心之後把當前點去掉,然後在子樹遞迴找重心,複雜度nlogn(就是sum_layer)。每個點被遍歷的次數正比於其layer。
const int MAXN = 2e5 + 10;
int n;
vector<int> G[MAXN];
int center, center_max_siz;
int siz[MAXN];
int layer[MAXN];
void find_center (int u, int p, int cur_n) {
siz[u] = 1;
int max_siz = 0;
for (const int &v : G[u]) {
if (v == p || layer[v] != 0) {
continue;
}
find_center (v, u, cur_n);
siz[u] += siz[v];
cmax (max_siz, siz[v]);
}
cmax (max_siz, cur_n - siz[u]);
if (center == 0 || max_siz < center_max_siz) {
center = u;
center_max_siz = max_siz;
}
}
void find_all_centers (int root, int cur_n, int l) {
if (layer[root] != 0) {
return;
}
center = 0, center_max_siz = INF;
find_center (root, 0, cur_n);
layer[center] = l;
find_center (center, 0, cur_n); // 重新計算正確的siz[v]
for (const int &v : G[center]) {
find_all_centers (v, siz[v], l + 1);
}
}
void solve() {
RD (n);
for (int i = 1; i <= n; ++i) {
G[i].clear();
layer[i] = 0;
}
for (int i = 1; i <= n - 1; ++i) {
int u, v;
RD (u, v);
G[u].push_back (v);
G[v].push_back (u);
}
find_all_centers (1, n, 1);
ll sum_layer = 0;
for (int i = 1; i <= n; ++i) {
sum_layer += layer[i];
}
WT (sum_layer);
WTN (layer, n);
}