【CF468D】 Tree

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;
}

posted @ 2022-09-28 10:45  azzc  阅读(15)  评论(0编辑  收藏  举报