CF1311E Construct the Binary Tree
给定树的节点数n和d,构造一颗二叉树,使所有节点的的深度和为d
容易得出n个节点的二叉树每个节点深度的总和最大为n*(n-1)/2,最小值为满二叉树的情况
于是就可以愉快地判断答案是否存在啦,然后还得构造出一个合法的答案qwq
我的方法是先弄成一条链再进行调整
反正数据不大,不如简单点每次只调整一个 没有儿子 的节点,使其深度减少1(用c数组表示一个节点的儿子个数)
具体做法就是先枚举一个没有儿子的节点x,然后枚举一个儿子不满且深度比x小2的节点y,将x移动为y的儿子,移动后要更新一些信息(看代码)
这样做看似复杂度爆炸(n^3),但事实上由于数据范围的约束,当n较大时d无法满足大于可能最小值的条件,并不用执行之后复杂度爆炸的过程 >_<
稍稍优化一下,如果一个节点已经无法移动(深度更小的位置已经满了),就做一个标记,避免下次又选到这个点做无用功
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int dep[N], fa[N], c[N], k[N];
signed main() {
int t; scanf ("%d", &t);
while (t--) {
int n, d; scanf ("%d %d", &n, &d);
if (d > n * (n - 1) / 2) { puts ("NO"); continue; }
int tmp = n - 1, mn = 0;
for (int i = 1; ; ++i) {
if (tmp < (1 << i)) { mn += i * tmp; break; }
tmp -= (1 << i), mn += i * (1 << i);
} if (d < mn) { puts ("NO"); continue; } puts ("YES");
for (int i = 1; i <= n; ++i)
fa[i] = i - 1, dep[i] = i - 1, c[i] = 1, k[i] = 0; c[n] = 0;
int now = n * (n - 1) / 2;
while (now > d) {
int p, ok = 0, tmp;
for (int i = 1; i <= n; ++i) if (!k[i] && !c[i]) { p = i; break; }
for (int i = 1; i <= n; ++i)
if (c[i] < 2 && dep[i] == dep[p] - 2) { tmp = i; ok = 1; break;}
if (!ok) { k[p] = 1; continue; } //如果节点已经无法移动就打个标记,防止TLE
--c[fa[p]], ++c[tmp], --dep[p], fa[p] = tmp, --now; //更新节点信息
} for (int i = 2; i <= n; ++i) printf ("%d ", fa[i]); puts ("");
} return 0;
}