详细讲解Codeforces Round #624 (Div. 3) E. Construct the Binary Tree(构造二叉树)

题意:给定节点数n和所有节点的深度总和d,问能否构造出这样的二叉树。能,则输出“YES”,并且输出n-1个节点的父节点(节点1为根节点)。
题解:n个节点构成的二叉树中,完全(满)二叉树的深度总和最小,单链树(左/右偏数)的深度总和最大。若d在这个范围内,则一定能构造出来;否则一定构造不出来。
1.初始构造一颗单链树,依次把底部的节点放入上面的层,直到满足深度总和为d
2.若当前深度总和sum > d,则先拿掉底端节点。
拿掉后,若sum依然比d大,就直接把底端节点放入有空位的最上层;
拿掉后sum <= d,dif = d - sum。
若dif >= 此时有空位的最上层深度,则深度为dif的层一定有空位,把底端节点放入该层,即可完成构造。
否则,依然把底端节点放入有空位的最上层,修改后的sum依旧比d大,继续循环即可。
3.退出循环后就完成了构造,获得了所求的树。
具体存储结构、表示方式和算法过程见代码(和注释):
#include<cstdio>
#include<cstring>
using namespace std;
/*
9 21
YES
1 1 2 2 4 4 6 8
9 22
YES
1 1 2 2 4 6 6 7
*/
int layer[], num[]; //layer[i]先存第i+1个点所在层的深度,num[i]是深度为i的层里的节点数 int main() {
int t, n, d;
scanf("%d", &t);
while (t--) {
scanf("%d%d", &n, &d);
memset(num, , sizeof num);
int sum = n * (n - ) / , dep = , minn = ;
num[] = ; //0深度层只有一个根节点
for (int i = ; i <= n; i++) {
//i&(i - 1)的结果为把i二进制下最后一个1置0。i&(i - 1) == 0时,i为2的整数次幂
if ((i&(i - )) == )dep++; //第i+1层的第一个节点为2^i
minn += dep; //minn记录满二叉树时的深度总和 layer[i - ] = i - ; //单链树时,和为sum,layer[i]是第i+1个点所在层的深度
num[i - ] = ; //num[i]记录深度为i的层的节点总数
}
if (d<minn || d>sum) {
puts("NO");
continue;
}
puts("YES");
dep = ; //当前有空位的最上层的深度
for (int i = n - ; i > && sum > d; i--) {
sum -= i; //拿掉底端顶点
num[i]--;
if (sum > d) { //拿掉之后,sum仍然比d大时;直接放最上面
layer[i] = dep; //第i+1个点现在的深度为dep
sum += dep; if (++num[dep] == ( << dep))dep++; //若最上面的层满了,修改为下一层
}
else { //拿掉之后,sum<=d时
int dif = d - sum; //看差值对应的层是否有空位
if (dif >= dep) { //有空位,则直接放到深度等于差值的那一层,构造成功
layer[i] = dif;
sum += dif; //写出来更好理解
num[dif]++; //该层节点数++
break;
}
else { //无空位,只能放最上面dep层
layer[i] = dep;
sum += dep; //此时sum仍然 > d
if (++num[dep] == ( << dep))dep++; //若最上面的层满了,修改为下一层
}
}
}
//构造成功。layer[i]是原来单链树中深度为i的点(第i+1个点) 现在的深度,num[i]是第i层的节点总数
//现只用num中的信息求解;layer中的信息只是辅助理解,现在用来存最终答案(即第i个节点的父节点编号)
int id(), fid(); //当前节点编号,上一层首个节点的编号
for (int i = ; num[i]; i++) { // while(深度为i的层节点数不为0)
for (int j = ; j < num[i]; j++) {
//深度为i的层的第j个节点,在完全二叉树中的编号为(1<<i)+j,上一层首个节点编号为1<<(i - 1)
//layer[id++] = fid + ((1 << i) + j) / 2 - (1 << (i - 1)); 直接算这个式子会溢出
layer[id++] = fid + j / ; //简化后得出,也可以直接理解推出来
}
fid += num[i - ];
}
for (int i = ; i < n; i++)
printf("%d ", layer[i]);
printf("%d\n", layer[n]);
}
return ;
}
附 完全二叉树编号:
1
2 3
4 5 6 7
8 9 10 11 12 13 14 15
详细讲解Codeforces Round #624 (Div. 3) E. Construct the Binary Tree(构造二叉树)的更多相关文章
- 详细讲解Codeforces Round #624 (Div. 3) F. Moving Points
题意:给定n个点的初始坐标x和速度v(保证n个点的初始坐标互不相同), d(i,j)是第i个和第j个点之间任意某个时刻的最小距离,求出n个点中任意一对点的d(i,j)的总和. 题解:可以理解,两个点中 ...
- Codeforces Round #624 (Div. 3)(题解)
Codeforces Round #624 (Div.3) 题目地址:https://codeforces.ml/contest/1311 B题:WeirdSort 题意:给出含有n个元素的数组a,和 ...
- Codeforces Round #624 (Div. 3) F. Moving Points 题解
第一次写博客 ,请多指教! 翻了翻前面的题解发现都是用树状数组来做,这里更新一个 线段树+离散化的做法: 其实这道题是没有必要用线段树的,树状数组就能够解决.但是个人感觉把线段树用熟了会比树状数组更有 ...
- Codeforces Round #624 (Div. 3) C. Perform the Combo(前缀和)
You want to perform the combo on your opponent in one popular fighting game. The combo is the string ...
- Codeforces Round #624 (Div. 3)
A.题意:通过加奇数减偶数的操作从a到b最少需要几步 签到题 #include <algorithm> #include <iostream> #include <cst ...
- Codeforces Round #624 (Div. 3) B. WeirdSort(排序)
output standard output You are given an array aa of length nn . You are also given a set of distinct ...
- Codeforces Round #624 (Div. 3) D. Three Integers
You are given three integers a≤b≤ca≤b≤c . In one move, you can add +1+1 or −1−1 to any of these inte ...
- Codeforces Round #624 (Div. 3) A. Add Odd or Subtract Even(水题)
You are given two positive integers aa and bb . In one move, you can change aa in the following way: ...
- Codeforces Round #624 (Div. 3) F
题意: 给出n的质点,带着初位置和速度: 如果中途两点可以相遇dis(i,j)=0: 如果不可以相遇,mindis(i,j): 求n个点的两两质点最小dis(i,j)之和 思路: 因为当初位置x和速度 ...
随机推荐
- CQOI十二省联考游记
Day 0 看似稳如老狗的我实则慌得一逼 看了一上午的CRT,一个字没看进去 我反复安慰自己:我才高一,我才高一 但是,明年的联赛会不会跟今年一样高呢? 明年的心态会不会有现在这么好呢? 明年同届的d ...
- 内网IP的解释
https://baike.baidu.com/item/%E5%86%85%E7%BD%91ip/8881186?fr=aladdin
- ios---CoreLocation框架实现定位功能
CoreLocation框架实现定位功能(iOS8.0之后) // // ViewController.m // 定位 // // Created by admin on 2017/9/20. // ...
- pku-3321 Apple Tree(dfs序+树状数组)
Description There is an apple tree outside of kaka's house. Every autumn, a lot of apples will grow ...
- 使用xpath总是找不到
今天使用使用xpath,直接从网页上复制的 /html/body/div[3]/div[2]/div[2]/div[3]/table/tbody/tr[2]/td[3]/a 但是在代码中总是找不到文件 ...
- Shiro身份验证及授权(二)
一.Shiro 身份验证 身份验证的步骤: 收集用户身份 / 凭证,即如用户名 / 密码: 调用 Subject.login 进行登录,如果失败将得到相应的 AuthenticationExcepti ...
- abp vnext2.0核心组件之领域实体组件源码解析
接着abp vnext2.0核心组件之模块加载组件源码解析和abp vnext2.0核心组件之.Net Core默认DI组件切换到AutoFac源码解析集合.Net Core3.1,基本环境已经完备, ...
- Ceph 存储集群5-数据归置
一.数据归置概览 Ceph 通过 RADOS 集群动态地存储.复制和重新均衡数据对象.很多不同用户因不同目的把对象存储在不同的存储池里,而它们都坐落于无数的 OSD 之上,所以 Ceph 的运营需要些 ...
- python中更人性化的一个单元测试框架:nose2
如果你学过 python 进行自动化测试,你一定使用过 unittest.今天我们要讲的 nose2 是一个高级版本的 unittest.他比 unittest 更容易理解,用起来也更加方便一些. 快 ...
- Codeforces_794
A.统计两个guard之间的钞票数. #include<bits/stdc++.h> #define MOD 1000000009 using namespace std; int a,b ...