CF1311E - Construct the Binary Tree 构造

8 篇文章 0 订阅
2 篇文章 0 订阅

CF1311E - Construct the Binary Tree

题意

构造 N N N个点,所有点深度之和为 D D D的二叉树

题解

考虑以下两种情况
N N N个点深度之和最小
这种就是每一层都是满的,这个等等算
N N N个点深度之和最大
链状, N N N个点组成直线,深度之和为 N ∗ ( N − 1 ) / 2 N*(N-1)/2 N(N1)/2

那么我们现在要构造一颗深度之和为 D D D的二叉树
那么这个深度 m i n ≤ D ≤ m a x min\leq D \leq max minDmax才有解

这里有两个方向
m a x max max -> m a x − 1 max-1 max1,从最大的开始,每次减一
m i n min min -> m i n + 1 min+1 min+1,从最小的开始,每次加一

这里是第二种方向
我们先确定每一层二叉树的点数量
然后根据关系式,上一层点数*2>=当前层点数
如果上一层减一个仍然满足这个式子,那就从上一层拿一个放到当前层

代码

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define sz  sizeof
#define eps 1e-9
#define lowbit(x) x&-x
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int MAX = 5e3 + 10;

int T, N, D;
int num[MAX], ans[MAX];

void solve() {
    if (D > (N - 1) * N / 2) {
        printf("NO\n");
        return;
    }
    memset(num, 0, sz(num));
    //初始状态的构建
    num[0] = 1;
    for (int i = 2; i <= N; i++)//将N-1个点放满二叉树
        for (int j = 1; j <= N; j++)
            if (num[j] + 1 <= 2 * num[j - 1]) {//当前层多一个点满足式子,我就多一个
                num[j]++;
                D -= j;
                break;
            }
    if (D < 0) {
        printf("NO\n");
        return;
    }
    while (D--) {
        for (int i = 1; i <= N; i++)
            if (num[i] + 1 <= 2 * (num[i - 1] - 1)) {//当前层多一个点,上面层少一个仍然满足式子
                //将下移动一个到上
                num[i]++, num[i - 1]--;
                break;
            }
    }
    printf("YES\n");
    int tot = 1, now = 1;
    for (int i = 1; i <= N; i++) {
        int pre = now + 1;
        for (int j = 0; j < num[i]; j++)
            ans[++now] = tot + j / 2;
        tot = pre;
    }
    for (int i = 2; i <= N; i++)
        printf("%d%s", ans[i], i == N ? "\n" : " ");
}

int main() {
    scanf("%d", &T);
    while (T--) {
        scanf("%d%d", &N, &D);
        solve();
    }

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值