Codeforces Round #624 (Div. 3) E. Construct the Binary Tree(二叉树模拟)

题目链接
在这里插入图片描述
思路:我们可以发现要想一棵n个节点的二叉树的深度和是有范围的,最大的就是一条链的情况,最小的就是树的结构是完全二叉树的时候,只要是在这个范围内的一定可以构造出来。那么怎么构造呢,我们首先构造最长的就是一条链,然后从最深的节点依次往前(每次往前深度就会减1),一直模拟这个过程,等于d的时候停止就好了。一开始不知道怎么模拟从后往前的过程,其实不用那么麻烦,我们用一个vector存一下i深度时存哪些节点就好了。

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=5e3+10; 
set<int>s[maxn];
vector<int>g[maxn];
int main()
{
	int T,n,d,low,ans,flag,p[maxn],m,parent[maxn],minn;
	scanf("%d",&T);
	while(T--)
	{
		ll k=1;
		minn=flag=0;
		scanf("%d%d",&n,&d);
		ans=n*(n-1)/2; 
		for(int i=0;i<31;++i) if((k<<i)>n) {low=i;break;}
		low--;
		for(int i=0;i<=low;++i) p[i]=(k<<i);
		for(int i=0;i<low;++i) minn+=i*p[i];
		minn+=low*(n-p[low]+1);
		if(d>ans||d<minn)
		{
			puts("NO");continue;
		}
		d=ans-d;
		for(int i=0;i<n;++i) s[i].clear(),g[i].clear();
		for(int i=0;i<n;++i) s[i].insert(i+1);
		for(int i=n-1;i>low;--i)
		{
			if(flag||d<=0) break;
			for(int j=i-1;j>=0;--j)
			{
				if(j<=low&&s[j].size()==p[j]) {m=j;break;}
				d--;
				if(d<=0) {s[i].erase(i+1),s[j].insert(i+1);flag=1;break;}
			}
			if(d>0) s[i].erase(i+1),s[m+1].insert(i+1);
			else break;
		}
		for(int i=0;i<n;++i) 
		{
			for(auto it=s[i].begin();it!=s[i].end();it++)
			g[i].push_back(*it);
		}
		for(int i=1;i<n;++i)
		{
			int cnt=0;
			for(int j=0;j<g[i].size();++j)
			{
			parent[g[i][j]]=g[i-1][cnt];
			if(j%2==1) cnt++;
			}
		}
		puts("YES");
		for(int i=2;i<=n;++i) printf("%d%s",parent[i],(i==n)?"\n":" ");
	}
}
发布了144 篇原创文章 · 获赞 0 · 访问量 4942

猜你喜欢

转载自blog.csdn.net/qq_42479630/article/details/104524108