【图论】树的直径
const int MAXN = 2e5 + 10;
vector<int> G[MAXN];
int dis[MAXN], mxdis;
void dfs(int u, int p) {
dis[u] = dis[p] + 1;
if(dis[u] > dis[mxdis])
mxdis = u;
for(int v : G[u]) {
if(v == p)
continue;
dfs(v, u);
}
}
int getDiameter(int root = 1) {
mxdis = 0;
dfs(root, 0);
root = mxdis;
mxdis = 0;
dfs(root, 0);
return dis[mxdis];
}
树的直径中心
这个直径中心和重心不一样,重心是要让每个子树的size尽可能平均,直径中心是让深度尽可能平均。不过其实用起来估计是差不多的。
下面的方法展示的就是把一棵树,最高级的中心设为A,低一级的中心设为B。虽然复杂度是错的,层数也远远不止log层,但是其实hack掉的数据还是不太好被出题人想到的。(其实是一堆长度递增的链竖着吊下来,然后横着头和头接在一起,每次让直径都没有减少,所以直径有多大就会遍历多少层,估计是要遍历根号n次?)谨慎使用!
下面的layer的最大值超过了题目限制的26。不过复杂度看起来还可以?每个点的layer恰好等于它被遍历的次数。正解要用树的重心去做。
模板题是这个:https://codeforces.com/contest/321/problem/C
这个题我一开始觉得是用直径的中心去做,但是按直径划分的话子树的直径不见得就是原树直径的1/2。可能只减少几个点甚至还会完全一样。
比如:
6 - 5 - 4 - 3 - 2 - 1 - 2 - 3 - 4 - 5 - 6
6 5 4 3 2
6 5 4 3
6 5 4
6 5
6
当前直径为13,去掉了1之后其实左边的直径还有10。并不是除以2。
https://codeforces.com/contest/321/problem/C
const int MAXN = 2e5 + 10;
int n;
vector<int> G[MAXN];
int dep[MAXN];
int layer[MAXN];
int find_max_dep_leaf (int u, int p) {
dep[u] = dep[p] + 1;
int max_dep_leaf = u;
for (const int &v : G[u]) {
if (v == p || layer[v] != 0) {
continue;
}
int leaf = find_max_dep_leaf (v, u);
if (dep[leaf] > dep[max_dep_leaf]) {
max_dep_leaf = leaf;
}
}
return max_dep_leaf;
}
int find_center (int u, int p, int max_dep_leaf) {
if (u == max_dep_leaf) {
return max_dep_leaf;
}
for (const int &v : G[u]) {
if (v == p || layer[v] != 0) {
continue;
}
int res = find_center (v, u, max_dep_leaf);
if (res == 0) {
continue;
}
if (dep[u] == (dep[max_dep_leaf] + 1) / 2) {
res = u;
}
return res;
}
return 0;
}
void find_all_centers (int root, int l) {
if (layer[root] != 0) {
return;
}
int leaf1 = find_max_dep_leaf (root, 0);
int leaf2 = find_max_dep_leaf (leaf1, 0);
int center = find_center (leaf1, 0, leaf2);
layer[center] = l;
for (const int &v : G[center]) {
find_all_centers (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, 1);
ll sum_layer = 0;
for (int i = 1; i <= n; ++i) {
sum_layer += layer[i];
}
WT (sum_layer);
WTN (layer, n);
}