题意
给定一棵 \(n\) 个节点的树,要求构造出一个点权序列 \(E\),满足以下三个条件:
1.所有 \(E_i\ge 1(1\le i\le n)\)。
2.对于任意一组 \((i,j)(1 ≤ i < j ≤ N)\),使 \(|E_i-E_j|\ge dist(i,j)\),\(dist\) 即树上两点距离。
3.使 \(E\) 中的最大值最小。
题解
首先考虑前两个条件,设存在长度为 \(n\) 排列 \(p\),使得 \(\forall i \in \left[1, n\right) E_{p_i} < E_{p_{i + 1}} \land E_{p_{i + 1}} - E_{p_i} \le dist\left(p_i, p_{i + 1}\right)\)。因为对于树上任意三点 \(i, j, k\),都有
所以对于任意 \(1 \le i < k < j \le n\),有
因此可以得到一个满足前两个要求的构造方法,对于任意 \(1 \le i < n\),构造 \(E_{p_i},E_{p_{i + 1}}\) 使得 \(E_{p_{i + 1}} - E_{p_i} = dist(p_i, p_{i + 1})\)。
接下来考虑第三个要求,对于排列 \(p\),序列 \(E_i\) 的最大值为
考虑到 \(\sum\limits_{i = 1}^{n - 1} dist(p_{i + 1}, p_i) + dist(p_1, p_n) + 1\) 的最小值为 \(2\left(n - 1\right) + 1\),即欧拉回路的长度,此时每个边都被经历两次,考虑在此基础上最大化 \(dist(p_1, p_n)\),显然满足 \(dist(x, y)\) 最大的 \(x, y\) 为树的直径的两个端点。
这样我们就得到了最终的构造方法:求出树的直径,然后从直径的一个端点进行欧拉环游,其中对于每个经过的节点,如果存在一条边在树的直径上,那么最后经过这条边。这样在到达直径的另一个端点时,可以保证所有节点均已访问过,故可以直接结束递归。
Code
#include <bits/stdc++.h>
typedef int valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;
typedef std::vector<bool> bitset;
valueType N;
ValueMatrix G;
ValueVector depth;
valueType dfs(valueType x, valueType from) {
valueType maxDepth = x;
depth[x] = depth[from] + 1;
for (auto const &iter: G[x]) {
if (iter == from)
continue;
valueType const result = dfs(iter, x);
if (depth[result] > depth[maxDepth])
maxDepth = result;
}
return maxDepth;
}
bitset tag;
bool addTag(valueType x, valueType from, const valueType &target) {
if (x == target)
return tag[x] = true;
for (auto const &iter: G[x]) {
if (iter == from)
continue;
if (addTag(iter, x, target))
tag[x] = true;
}
return tag[x];
}
ValueVector ans;
valueType dfsCount = 0;
void calc(valueType x, valueType from) {
ans[x] = ++dfsCount;
valueType end = -1;
for (auto const &iter: G[x]) {
if (iter == from)
continue;
if (tag[iter]) {
end = iter;
continue;
}
calc(iter, x);
++dfsCount;
}
if (end != -1) {
calc(end, x);
++dfsCount;
}
}
int main() {
std::cin >> N;
G.resize(N + 1);
depth.resize(N + 1, 0);
for (valueType i = 1; i < N; ++i) {
valueType a, b;
std::cin >> a >> b;
G[a].emplace_back(b);
G[b].emplace_back(a);
}
std::fill(depth.begin(), depth.end(), 0);
valueType const A = dfs(1, 0);
std::fill(depth.begin(), depth.end(), 0);
valueType const B = dfs(A, 0);
tag.resize(N + 1, false);
addTag(A, 0, B);
ans.resize(N + 1, 0);
calc(A, 0);
for (valueType i = 1; i <= N; ++i)
std::cout << ans[i] << " ";
std::cout << std::endl;
return 0;
}