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;
}