Codeforces 1311E Construct the Binary Tree

Description

要求构造一个 $n$ 个节点的二叉树(每个节点拥有不超过 $2$ 个孩子),节点 $1$ 为根,要使所有节点到根的距离之和为 $d$ 。要求先判断可不可以构造,如果可以输出 YES,下一行输出 $2$ 到 $n$ 号节点的父亲节点,否则输出 NO。有多组询问。

Solution

首先,我们可以先确定可行的 $d$ 的范围。

显然,当二叉树是一条链的时候,$d$ 是最大的,也就是说,$0+1+2+\cdots (n-1) = d_{\max}$,稍微转化一下,就是 $d \le \frac{n(n-1)}{2}$。

而把这颗二叉树给尽量满的构造 $d$ 显然是最小的,也就是说,确保这棵二叉树是完全二叉树,就可以得到 $d_{\min}$,这个不妨递推一下,如果用 $dep_i$ 表示第 $i$ 个结点的深度,那么显然有 $dep_{2i} = dep_i + 1, dep_{2i+1} = dep_i + 1$(类比线段树很容易理解),当然,这个和 $dep_i = dep_{\lfloor\frac i 2 \rfloor}+1$ 是等价的。

那么在 $[d_{\min}, d_{\max}]$ 之间的 $d$ 都是可行的了,观察到 $n, d$ 都很小,可以尝试一步步的转移。先构造出一棵完全二叉树,每次 找到一个可行的深度最大的点,把它向下移动一层

为了实现方便,不妨把 $dep = i$ 的点存到一个 vector 中,名字叫做 $\text{node}_i$,现在试图把某一个 $dep = i$ 的点下移,要求显然就是 去掉这个点后,下面一层还有位置,可以表现为 $\operatorname{size}(\text{node}_{i+1})<(\operatorname{size}(\text{node}_i) - 1) \times 2$,暴力下移即可。

最后我们得到的是若干个 vector 数组,令 $\text{node}_{i,j}$ 的儿子是 $\text{node}_{i+1,2i}$ 和 $\text{node}_{i+1,2i+1}$ 就行了(当然,前提是存在)。

#include <bits/stdc++.h>
using namespace std;
const int N = 5005;
int n, dep[N], d, mxdep, sumdep, fa[N];
vector<int> node[N];
int main()
{
    int t;
    cin >> t;
    while(t--)
    {
        cin >> n >> d;
        for(int i = 1; i <= n; i++) node[i].clear();
        dep[1] = mxdep = sumdep = 0;
        node[0].push_back(1);
        for(int i = 2; i <= n; i++)
        {
            dep[i] = dep[i >> 1] + 1;
            sumdep += dep[i];
            mxdep = max(mxdep, dep[i]);
            node[dep[i]].push_back(i); 
        }
        if(d < sumdep || d > n * (n - 1) / 2)
        {
            cout << "NO\n";
            continue;
        }
        while(sumdep < d)
        {
            for(int i = mxdep; ~i; i--)
            {
                if(node[i].size() >= 2 && node[i + 1].size() < node[i].size() * 2 - 2)
                {
                    sumdep++;
                    mxdep = max(mxdep, i + 1);
                    node[i + 1].push_back(node[i].back());
                    node[i].pop_back();
                    break;
                }
            }
        }
        for(int i = 0; i <= mxdep; i++)
        {
            for(int j = 0; j < node[i].size(); j++)
            {
                int ls = j * 2, rs = j * 2 + 1;
                if(ls < node[i + 1].size()) fa[node[i + 1][ls]] = node[i][j];
                if(rs < node[i + 1].size()) fa[node[i + 1][rs]] = node[i][j];
            }
        }
        cout << "YES" << endl;
        for(int i = 2; i <= n; i++) cout << fa[i] << ' ';
        cout << endl;
    }
}
posted @ 2020-04-29 21:51  syksykCCC  阅读(137)  评论(0编辑  收藏  举报