CF468D Tree
- 以树的重心为根
- i和pi不能在同一个子树中
- 贪心求出方案
点击查看代码
</details>
#include <set>
#include <stdio.h>
#include <string.h>
#include <algorithm>
const int N = 1e5 + 5, M = N << 1;
typedef long long LL;
int n, h[N], e[M], w[M], nxt[M], idx;
int rt;
void add(int a, int b, int c) {
e[++ idx] = b, w[idx] = c, nxt[idx] = h[a], h[a] = idx;
}
int dfs(int u, int fa) {
int sz = 1, mx = 0;
for(int i = h[u]; i; i = nxt[i]) {
int v = e[i];
if(v == fa) continue;
int sv = dfs(v, u);
sz += sv, mx = std::max(mx, sv);
}
if(std::max(mx, n - sz) <= (n >> 1)) rt = u; // 树的重心
return sz;
}
std::set<int> in[N]; // 每个子树中未匹配的i的编号
std::set<int> min; // 每个子树中未匹配的编号最小的i
std::set<std::pair<int, int> > set; // 每个子树中未匹配的i和pi的和 及 编号
int fore[N]; // 最远非根祖先
int fa[N]; // 父节点
int sum[N];
long long ans, dist;
void dfs(int u) {
ans += dist;
for(int i = h[u]; i; i = nxt[i]) {
int v = e[i];
if(v == fa[u]) continue;
fa[v] = u;
dist += w[i];
dfs(v);
dist -= w[i];
}
}
int frt;
void calc(int u) { // 预处理
in[fore[u] = frt].insert(u); // 开始的时候没有匹配
for(int i = h[u]; i; i = nxt[i]) {
int v = e[i];
if(v == fa[u]) continue;
calc(v);
}
}
void link(int x, int y) {
int fx = fore[x], fy = fore[y];
min.erase(y);
if(fx) {
set.erase({sum[fx], fx});
set.insert({-- sum[fx], fx});
}
if(fy) {
in[fy].erase(y);
if(in[fy].size()) min.insert(*in[fy].begin());
set.erase({sum[fy], fy});
set.insert({-- sum[fy], fy});
}
}
int main() {
scanf("%d", &n);
for(int i = 1, a, b, c; i < n; i ++) {
scanf("%d%d%d", &a, &b, &c);
add(a, b, c), add(b, a, c);
}
dfs(1, -1), dfs(rt);
printf("%lld\n", ans << 1);
if(n == 1) return puts("1"), 0;
min.insert(rt);
for(int i = h[rt]; i; i = nxt[i]) {
int u = e[i];
frt = u, calc(u);
min.insert(*in[u].begin());
set.insert({sum[u] = in[u].size() << 1, u});
}
for(int u = 1; u <= n; u ++) {
int res;
if(set.rbegin()->first == n - u + 1 && set.rbegin()->second != fore[u])
res = *in[set.rbegin()->second].begin();
else {
if(fore[*min.begin()] != fore[u] || u == rt) res = *min.begin(); // 不在一个子树
else res = *++min.begin(); // 在一个子树: 找下一个
}
link(u, res);
printf("%d ", res);
}
return 0;
}