CF-Round#624-div3-E题
E. Construct the Binary Tree
这道题构造题。
构造一颗二叉树。
题目大意:给你结点个数和总深度。问是否能够构造出满足要求结点个数和深度的树,这里的深度定义为每个结点到根结点的路径长度总和。
我们可以直接初始化这颗树为一条单链。这条单链的深度是这n个结点的最大深度上限。如果超过了这个上限。直接输出NO即可
还有一种情况,就是结点个数很多。但是深度要求很小。这种情况也无法构造出符合要求的二叉树。这种情况也需要输出NO,但是这种情况可以放在后面一起处理
初始化单链以后,我们逐次将最下面的结点放在适合的位置,最后跑一遍父结点即可。
我们用ans[]保存当前结点的深度。结点1~n对应于下标0-n-1;
nowdep表示当前可以放结点的最小深度
maxx表示当前深度的最大结点个数
c就是当前深度的操作到了哪一个结点
函数get_dep()表示当前可以得到的最小的深度。极限位置。
这个地方可以处理上面输出NO的情况
如果当前结点所在深度小于等于函数返回来最小深度。代表还需要把当前结点往下移。显然这种情况是不成立的。输出NO即可
用tmp保存还差多少的深度达到满足要求的条件深度和
用条件分支判断一下。如果当前结点的深度-最小的深度还是小于tmp的话,直接把当前结点移动到最小深度的位置。对应于多次操作。否则直接一步到位即可。
最后处理一下父结点
fa[]保存父结点,代码部分是0~n-1保存的。输出的时候++就行了。
二重循环找到每个结点深度相等的地方。并且判断当前结点的儿子个数小于2.否则需要接到同等深度的另外的结点上面。
最后输出就可以啦~
代码部分:
#include <bits/stdc++.h>
#define mst(a, n) memset(a, n, sizeof(a))
using namespace std;
const int N = 5e3 + 10;
int n, d;
int cnt, pos;
int nowdep, c, maxx;
int ans[N];
int ch[N];
int fa[N];
int get_dep()
{
int ans = nowdep;
c++;
if (c == maxx)
{
maxx *= 2;
c = 1;
nowdep++;
}
return ans;
}
int main()
{
int t;
cin >> t;
while (t--)
{
ans[0] = 0;
mst(ch, 0);
cin >> n >> d;
cnt = n * (n - 1) / 2;
for (int i = 1; i < n; i++)
{
ans[i] = i;
}
if (d > cnt)
{
cout << "NO\n";
continue;
}
nowdep = 1;
c = 1;
maxx = 2;
pos = n - 1;
while (cnt > d)
{
int tmp = cnt - d;
int dep = get_dep();
if (dep >= pos)
{
break;
}
if (tmp >= (pos - dep))
{
ans[pos] = dep;
cnt -= (pos - dep);
}
else
{
ans[pos] -= tmp;
cnt = d;
}
pos--;
}
if (cnt > d)
{
cout << "NO\n";
}
else
{
cout << "YES\n";
for (int i = 1; i < n; i++)
{
for (int j = 0; j < n; j++)
{
if (ans[j] == ans[i] - 1 && ch[j] < 2)
{
ch[j]++;
fa[i] = j;
break;
}
}
}
for (int i = 1; i < n; i++)
{
cout << fa[i] + 1 << " ";
}
cout << endl;
}
}
return 0;
}