CodeForces 1311E Construct the Binary Tree
阅读原文时间:2023年09月03日阅读:1

题意

给定\(n\)和\(d\),构造一颗\(n\)个节点的二叉树(以\(1\)为根),所有节点到\(1\)的距离和为\(d\),不行输出\(NO\),否则输出\(YES\)和\(2\)-\(n\)的父亲编号

分析

最大和显然是一条链,如果最大和仍小于\(d\),则不行,否则先构造出一条链,然后枚举当前的层数,如果当前层数的下一层仍然可以填,则将链的尾端放置在下一层可得到最大的变化,如果这个变化大于所需要的变化,则找到挂置的层数,否则则挂在下一层,若下一层已满,则将所枚举层数下移

#pragma GCC optimize(3, "Ofast", "inline")

#include <bits/stdc++.h>

using namespace std;

mt19937 rnd(chrono::high_resolution_clock::now().time_since_epoch().count());
#define start ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define ll long long
#define int ll
#define ls st<<1
#define rs st<<1|1
#define pii pair<int,int>
#define rep(z, x, y) for(int z=x;z<=y;++z)
#define com bool operator<(const node &b)
const int maxn = (ll) 5e3 + 5;
const int mod = 998244353;
const int inf = 0x3f3f3f3f;
int T = 1;
int pre[maxn];
set<int> lay[maxn];
vector<int> son[maxn];

void solve() {
    int n, d;
    cin >> n >> d;
    int now = 0;
    son[1].clear();
    lay[1].clear();
    lay[1].insert(1);
    rep(i, 2, n) {
        pre[i] = i - 1, now += i - 1, lay[i].clear();
        lay[i].insert(i);
        son[i].clear();
        son[i - 1].push_back(i);
    }
    if (now < d) {
        cout << "NO\n";
        return;
    }
    int nowLay = 1;
    for (int i = n; i >= 1; --i) {
        if (i <= nowLay + 1)
            break;
        int maxx = i - nowLay - 1;
        if (maxx >= now - d) {
            if (lay[i - 1 - (now - d)].empty()) {
                ++nowLay;
                ++i;
                continue;
            }
            int fa = *lay[i - 1 - (now - d)].begin();
            pre[i] = fa;
            now = d;
            break;
        } else {
            now -= maxx;
            int fa = *lay[nowLay].begin();
            son[fa].push_back(i);
            if (son[fa].size() == 2)
                lay[nowLay].erase(fa);
            son[pre[i]].erase(son[pre[i]].begin());
            pre[i] = fa;
            lay[nowLay + 1].insert(i);
            lay[i].erase(i);
            if (lay[nowLay].empty())
                ++nowLay;
        }
    }
    if (now != d) {
        cout << "NO\n";
        return;
    }
    cout << "YES\n";
    rep(i, 2, n)cout << pre[i] << ' ';
    cout << '\n';
}

signed main() {
    start;
    cin >> T;
    while (T--)
        solve();
    return 0;
}