[CF] CF1311E Construct the Binary Tree
Description
Solution
注意到深度和最小的情况就是完全二叉树,最大的就是链。那么我们先构造出一棵完全二叉树,再一步步调整节点变成链。
不妨令最初的链为\(1,2,4,...,2^k\)。设当前考虑到了点\(i\),链底为\(now\),目前深度和距离\(d\)还差\(r\)。
考虑到把\(i\)挂到\(now\)下面,深度增加了\(cnt=dep[now]+1-dep[i]\)。所以,如果\(cnt<r\),就可以把\(i\)直接挂过来,\(r-=cnt\)。
否则,说明如果挂过来,深度和会大于\(d\)。所以,我们要使\(cnt\)变小。
\(i\)不方便动,从而我们改变\(now\)即可。在\(cnt==r\)之前,不断使\(now=fa[now]\),从而\(cnt--\)。
最后依次输出即可。(数据太弱了,可以做到\(\sum{n}\leq{10^7}\)的)
Code
#include <bits/stdc++.h>
using namespace std;
int t, n, d, fa[5005], dep[5005];
int read()
{
int x = 0, fl = 1; char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') fl = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + ch - '0'; ch = getchar();}
return x * fl;
}
int main()
{
t = read();
while (t -- )
{
n = read(), d = read();
int sum = 0;
dep[1] = 0;
for (int i = 2; i <= n; i ++ )
{
fa[i] = i >> 1;
dep[i] = dep[fa[i]] + 1;
sum += dep[i];
}
if (sum > d)
{
puts("NO");
continue;;
}
if (sum == d)
{
puts("YES");
for (int i = 2; i <= n; i ++ )
printf("%d ", fa[i]);
puts("");
continue;
}
int r = d - sum, now = (int)(pow(2, (int)log2(n))), fl = 0;
for (int i = n; i >= 1; i -- )
{
if ((i & (i - 1)) == 0) continue;
int cnt = dep[now] + 1 - dep[i];
if (cnt < r)
{
fa[i] = now, now = i;
r -= cnt, dep[i] = dep[fa[i]] + 1;
}
else
{
while (r < cnt) {now = fa[now], cnt -- ;}
fl = 1; fa[i] = now; break;
}
}
if (!fl)
{
puts("NO");
continue;
}
puts("YES");
for (int i = 2; i <= n; i ++ )
printf("%d ", fa[i]);
puts("");
}
return 0;
}