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;
}
原文地址:https://www.cnblogs.com/whx666/p/12670503.html