标签:lse algorithm ace mamicode printf namespace include 图片 scan
https://nanti.jisuanke.com/t/42552
以上是交题网站计蒜客
本题要求找到所有子树的所有重心
性质1 : 两棵树合并,新树的重心在两旧树重心连线上
性质2 :子树的重心一定在重儿子上
性质3 :树上所有点到重心的距离的和最小
当siz[root] - siz[x] > siz[x] 时,x要往上爬 (某大佬的推理)
这种写法是每次都得都往上爬

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int maxn = 2e5 + 777;
struct Node {
int to;
int next;
}G[maxn * 2];
int z = 0;
int head[maxn];
int add(int x, int y) {
G[++z].to = y;
G[z].next = head[x];
head[x] = z;
return 0;
}
int n;
int dp[maxn];
int fa[maxn], siz[maxn];
int dep[maxn];
vector<int>ans[maxn];
int unin(int root, int x, int y) {
while (dep[x] > dep[root] && siz[root] - siz[x] > siz[x]) {//让x往上爬
x = fa[x];
}
while (dep[y] > dep[root] && siz[root] - siz[y] > siz[y]) {
y = fa[y];
}
if (dep[x] > dep[y]) dp[root] = x;
else dp[root] = y;
return 0;
}
int son[maxn];
int dfs(int x, int f,int d) {
int s = 0;
siz[x] = 1;
dep[x] = d;
fa[x] = f;
for (int i = head[x]; i; i = G[i].next) {
int p = G[i].to;
if (p == f) continue;
dfs(p, x, d + 1);
siz[x] += siz[p]; //先把x和p合并起来
unin(x, dp[x], dp[p]); //然后开始往上爬
}
return 0;
}
int main() {
int be, en;
scanf("%d", &n);
for (int i = 1; i < n; i++) {
scanf("%d%d", &be, &en);
add(be, en);
add(en, be);
}
for (int i = 1; i <= n; i++) dp[i] = i;
dfs(1, 0, 1);
for (int i = 1; i <= n; i++) {
int x = dp[i];
ans[i].push_back(x);
int t = fa[x];
if (t != 0 && siz[i] - siz[x] == siz[x]) {
ans[i].push_back(t);
}
sort(ans[i].begin(), ans[i].end());
if (ans[i].size() == 1) {
printf("%d\n", ans[i][0]);
}
else {
printf("%d %d\n", ans[i][0], ans[i][1]);
}
}
return 0;
}
这个是找到重儿子,从重儿向上爬,好理解一些,
这个更快一些

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int maxn = 2e5 + 777;
struct Node {
int to;
int next;
}G[maxn * 2];
int z = 0;
int head[maxn];
int add(int x, int y) {
G[++z].to = y;
G[z].next = head[x];
head[x] = z;
return 0;
}
int n;
int dp[maxn];
int fa[maxn], siz[maxn];
int dep[maxn];
vector<int>ans[maxn];
int unin(int root, int x, int y) {
while (dep[x] > dep[root] && siz[root] - siz[x] > siz[x]) {//让x往上爬
x = fa[x];
}
while (dep[y] > dep[root] && siz[root] - siz[y] > siz[y]) {
y = fa[y];
}
if (dep[x] > dep[y]) dp[root] = x;
else dp[root] = y;
return 0;
}
int son[maxn];
int dfs(int x, int f,int d) {
int s = 0;
siz[x] = 1;
dep[x] = d;
fa[x] = f;
for (int i = head[x]; i; i = G[i].next) {
int p = G[i].to;
if (p == f) continue;
dfs(p, x, d + 1);
siz[x] += siz[p]; //先把x和p合并起来
if (s < siz[p]) {
s = siz[p];
son[x] = p;
}
}
dp[x] = x;
if (!son[x]) return 0;
int p = dp[son[x]];//重儿子的重心
while (dep[p] > dep[x] && siz[x] - siz[p] > siz[p]) {//满足条件就向上怕,最多能到根
p = fa[p];
}
dp[x] = p;
return 0;
}
int main() {
int be, en;
scanf("%d", &n);
for (int i = 1; i < n; i++) {
scanf("%d%d", &be, &en);
add(be, en);
add(en, be);
}
dfs(1, 0, 1);
for (int i = 1; i <= n; i++) {
int x = dp[i];
ans[i].push_back(x);
int t = fa[x];
if (t != 0 && siz[i] - siz[x] == siz[x]) {
ans[i].push_back(t);
}
sort(ans[i].begin(), ans[i].end());
if (ans[i].size() == 1) {
printf("%d\n", ans[i][0]);
}
else {
printf("%d %d\n", ans[i][0], ans[i][1]);
}
}
return 0;
}
标签:lse algorithm ace mamicode printf namespace include 图片 scan
原文地址:https://www.cnblogs.com/lesning/p/12560509.html