Construct the Binary Tree CodeForces - 1311E(构造+模拟)

You are given two integers n and d. You need to construct a rooted binary tree consisting of n vertices with a root at the vertex 1 and the sum of depths of all vertices equals to d.

A tree is a connected graph without cycles. A rooted tree has a special vertex called the root. A parent of a vertex v is the last different from v vertex on the path from the root to the vertex v. The depth of the vertex v is the length of the path from the root to the vertex v. Children of vertex v are all vertices for which v is the parent. The binary tree is such a tree that no vertex has more than 2 children.

You have to answer t independent test cases.

Input
The first line of the input contains one integer t (1≤t≤1000) — the number of test cases.

The only line of each test case contains two integers n and d (2≤n,d≤5000) — the number of vertices in the tree and the required sum of depths of all vertices.

It is guaranteed that the sum of n and the sum of d both does not exceed 5000 (∑n≤5000,∑d≤5000).

Output
For each test case, print the answer.

If it is impossible to construct such a tree, print “NO” (without quotes) in the first line. Otherwise, print “{YES}” in the first line. Then print n−1 integers p2,p3,…,pn in the second line, where pi is the parent of the vertex i. Note that the sequence of parents you print should describe some binary tree.

Example
Input
3
5 7
10 19
10 18
Output
YES
1 2 1 3
YES
1 2 3 3 9 9 2 1 6
NO
Note
Pictures corresponding to the first and the second test cases of the example:
在这里插入图片描述
在这里插入图片描述
思路:我们可以计算出上限和下限。如果不在这个范围内就不能构造成功。在这个范围内的都可以构造成功。那么我们可以计算出差值来,首先的状态就是值最小的时候,然后一个一个的往下移动。但是要注意必须保证上面那一层的乘以2大于等于当前层,这样才符合二叉树的标准。就是一个模拟。我看网上大佬都是一条单链开始不断的减少自己的值,可能那样更好做一些。
代码如下:

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int maxx=5e3+100;
int a[maxx];
int ans[maxx];
int n,d;

inline int fcs(int i)
{
	int _max=0;
	while((a[i]-_max)*2>=(a[i+1]+_max)) _max++;
	return _max-1;
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		memset(a,0,sizeof(a));
		scanf("%d%d",&n,&d);
		int x=1,all=0;
		int _min=0;
		int cnt=0;
		while(all+x<=n)
		{
			_min+=((int)log2(x)*x);
			all+=x;
			a[++cnt]=x;
			x<<=1;
		}
		_min+=((int)log2(x)*((n-all)));
		a[++cnt]=n-all;
		int _max=(n)*(n-1)/2;
		if(!(d>=_min&&d<=_max)) cout<<"NO"<<endl;
		else
		{
			int cz=d-_min;
			while(cz)
			{
				for(int i=cnt;i>=2&&cz;i--)
				{
					if(a[i]>1)
					{
						int zz=fcs(i);//寻找可以下移的最大个数。
						if(zz<=cz) a[i+1]+=zz,a[i]-=zz,cz-=zz;
						else a[i+1]+=cz,a[i]-=cz,cz=0;
						if(i+1>cnt) cnt++;
					}
				}
			}
			//for(int i=1;i<=cnt;i++) cout<<a[i]<<" ";cout<<endl;
			vector<int> p[cnt+1];
			for(int i=1;i<=cnt;i++) p[i].clear();
			int z=2;
			for(int i=1;i<=cnt;i++)
			{
				if(i==1) p[i].push_back(1);
				else
				{
					for(int j=0;j<p[i-1].size()&&a[i];j++)
					{
						if(a[i]) ans[z++]=p[i-1][j],a[i]--,p[i].push_back(z-1);
						if(a[i]) ans[z++]=p[i-1][j],a[i]--,p[i].push_back(z-1);
					}
				}
			}
			cout<<"YES"<<endl;
			for(int i=2;i<=n;i++) cout<<ans[i]<<" ";cout<<endl;
		}
	}
	return 0;
}

努力加油a啊,(o)/~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

starlet_kiss

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值