[CF] CF1311E Construct the Binary Tree

Description

\(Link\)

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;
}
posted @ 2021-03-04 20:40  andysj  阅读(50)  评论(0编辑  收藏  举报