首页 > 其他分享 >【CF468D】 Tree

【CF468D】 Tree

时间:2022-09-28 10:58:40浏览次数:71  
标签:set min int fy Tree fore CF468D fx

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

标签:set,min,int,fy,Tree,fore,CF468D,fx
From: https://www.cnblogs.com/azzc/p/16737210.html

相关文章

  • CF468D Tree
    CF468DTree以树的重心为根i和pi不能在同一个子树中贪心求出方案点击查看代码</details>#include<set>#include<stdio.h>#include<string.h>#include<alg......
  • leetcode 617. Merge Two Binary Trees 合并二叉树(简单)
    一、题目大意给你两棵二叉树:root1和root2。想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉......
  • ABC 239 E - Subtree K-th Max(树+dfs)
    https://atcoder.jp/contests/abc239/tasks/abc239_e题目大意:给定一棵树,根节点是1,一共有n个节点,每一个节点都有它自己的值给定n-1条边,和q个询问问我们在第x个节点之......
  • 关于使用shutil.rmtree删除git文件夹时出现拒绝访问的问题
    简介在实际项目中发现,当使用shutil.rmtree删除整个git目录时会出现.git文件无法删除的情况,报错是拒绝访问,原因是默认情况下.git文件是只读的,无法直接对其进行操作。解决......
  • 【Vim】NERDTree目录导航与操作插件的使用方法
    【NERDTree目录导航】NERDTree中我们可以使用k/j上下移动键在文件/文件夹之间移动,但是当项目文件/文件夹很多时候,这种方式就显得很笨拙了。NERDTree提供了如下所示的快捷......
  • leetcode 208. Implement Trie (Prefix Tree) 实现 Trie (前缀树) (中等)
    一、题目大意Trie(发音类似"try")或者说前缀树是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补完和拼写检查。......
  • LeetCode 1382. Balance a Binary Search Tree
    原题链接在这里:https://leetcode.com/problems/balance-a-binary-search-tree/题目:Giventhe root ofabinarysearchtree,return a balanced binarysearchtre......
  • CF804D Expected diameter of a tree(期望+根号分治)
    tag期望,根号分治。大致题意:给你一个森林,每次询问两个点,求把两个点所在联通块连接起来生成的树的直径的期望。分析:如果是期望的话,只需要求出所有可能情况下的能生成的......
  • leetcode 669. Trim a Binary Search Tree 修剪二叉搜索树 (简单)
    一、题目大意给你二叉搜索树的根节点root,同时给定最小边界low和最大边界high。通过修剪二叉搜索树,使得所有节点的值在[low,high]中。修剪树不应该改变保留在树中的......
  • ABC 243 D - Moves on Binary Tree(树+字符串)
    https://atcoder.jp/contests/abc243/tasks/abc243_d题目大意:给定一颗完全二叉树,他总共可以有(2^10^100)-1个节点,节点下标为1,2,...,(2^10^100)-1。给我们一个长度为n......