[CoE R5] So What Do We Do Now?

题目背景

396ac9d3c58dbf329d6ead206944a5a495930006.jpg

\(\texttt{I’m getting tired of hiding.}\)

声明:上述图片取自网络,作者不明,如有侵权,告知即删。

题目描述

给定一棵 \(n\) 个结点的有根树,根结点编号为 \(1\)。设以 \(i\) 为根的子树为 \(T_i\)。你需要给每个结点赋一个正整数点权 \(v_i\),使得所有点的点权恰为 \(1,2,\dots,n\) 各一个。记

\[f=\sum_{i=1}^{n}R_i, \]

其中 \(R_i\) 是以 \(i\) 为根的子树中点权的极差,即

\[R_i=\max_{j \in T_i}\{v_j\}-\min_{j \in T_i}\{v_j\}. \]

对于所有的赋点权的方式,请求出一组使 \(f\) 取到最小值的点权。

输入格式

第一行一个正整数 \(n\) 表示树的结点数。

接下来 \(n-1\) 行,每行两个正整数 \(u,v\),表示 \(u,v\) 之间有一条边。

输出格式

第一行一个 \(1,2,\dots,n\) 的排列,表示结点 \(1,2,\dots,n\) 的点权。由于赋点权的方式可能有很多种,你只需要输出其中任意一种即可。

样例 #1

样例输入 #1

3
1 2
1 3

样例输出 #1

1 2 3

样例 #2

样例输入 #2

2
1 2

样例输出 #2

1 2

样例 #3

样例输入 #3

5
1 2
2 3
3 4
4 5

样例输出 #3

1 2 3 4 5

提示

样例说明

输入 \(\#1\)

graph.png

\(R_1=3-1=2,R_2=2-2=0,R_3=3-3=0,f=R_1+R_2+R_3=2\),可以证明,不存在使得 \(f\) 更小的构造。


数据范围

对于 \(10\%\) 的数据,\(n \le 10\)

对于另外 \(10\%\) 的数据,树是一条链;

对于另外 \(20\%\) 的数据,有一个结点与其他 \(n-1\) 个结点都相连;

对于另外 \(20\%\) 的数据,树是一棵完全二叉树,即除了叶子结点外每个结点都恰有两个子结点;

对于 \(100\%\) 的数据,\(1 \le n \le 10^6\)

思路

树上\(DP\),先建树,然后遍历整棵树,求出每棵子树的节点数,接着在求出答案,把一棵树拆成几个子树进行求解,这里要注意答案不一定从\(1\)开始存,所以要传一个变量,告诉函数从哪个地方开始存答案。
由于存答案时一棵子树的答案长度和子树大小相等,所以计算每个子树时,每算完一个子树,就要把开始存答案的位置加上子树大小。
然后就没有然后了。

代码

#include <iostream>
#include <cstring>
using namespace std;
const int N = 1000010,M = 2 * N;
int n;
int h[N],e[M],ne[M],idx;
int s[N];
int ans[N];
void add (int a,int b) {  //链式前向星
	e[idx] = b;
	ne[idx] = h[a];
	h[a] = idx++;
}
void get_size (int u,int fa) {  //这里传入父亲是防止死递归
	s[u] = 1;
	for (int i = h[u];~i;i = ne[i]) {
		int j = e[i];
		if (j == fa) continue;
		get_size (j,u);
		s[u] += s[j];  //加上子树大小
	}
}
void dfs (int u,int fa,int add) {
	ans[u] = add + 1;  //先存答案
	int t = add + 1;  //要加1,因为当前点已经存了数
	for (int i = h[u];~i;i = ne[i]) {
		int j = e[i];
		if (j == fa) continue;
		dfs (j,u,t);
		t += s[j];  //到下一个位置
	}
}
int main () {
	memset (h,-1,sizeof (h));
	cin >> n;
	for (int i = 1;i <= n - 1;i++) {
		int a,b;
		cin >> a >> b;
		add (a,b),add (b,a);
	}
	get_size (1,0),dfs (1,0,0);
	for (int i = 1;i <= n;i++) cout << ans[i] << ' ';
	cout << endl;
	return 0;
}

原文地址:http://www.cnblogs.com/incra/p/16794734.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性