首页 > 其他分享 >CF1311E 题解

CF1311E 题解

时间:2023-02-02 19:55:47浏览次数:42  
标签:ch int 题解 dep while Maxn CF1311E 二叉树

题意: 构造一个节点数为 \(n\) 的树, 使得节点深度之和为 \(d\). (根节点为 \(1\) 且深度为 \(0\))

显然, 不断构造二叉树并检查是否为答案是行不通的, 只能在 \(O(n)\) 的时间内构造, 不然就T了.

我们可以轻易得出构造的二叉树节点深度和最大是一条链的情况, 最小是满二叉树. 这道题, 我们可以由满二叉树转移至目标树.

考虑暴力的方法, 我们可以每次使总和加一, 只需将一个节点向下移即可. 为了保证其始终是一棵二叉树, 我们应该使节点尽量往左靠且尽可能能往下移使其构成一条链.

#include<cstdio>
#include<cmath>

#define Maxn 10000

using namespace std;

int T, n, d, fa[Maxn + 9], dep[Maxn + 9], id[Maxn + 9], deepest;
bool _true[Maxn + 9];

int read() {
	int sum = 0, f = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') sum = (sum << 3) + (sum << 1) + ch - '0', ch = getchar();
	return sum * f;
}

void write(int x) {
	if(x < 0) putchar('-'), write(-x);
	else if(x <= 9) putchar(x + '0');
	else write(x / 10), putchar(x % 10 + '0');
}

void Run() {
	n = read(), d = read();
	int need = d;
	for(int i = 1; i <= n; ++i) {
		_true[i] = 0;
		need -= dep[i];
		int leftson = i << 1, rightson = i << 1 | 1;
		if(leftson <= n) fa[leftson] = i, dep[leftson] = dep[i] + 1;
		if(rightson <= n) fa[rightson] = i, dep[rightson] = dep[i] + 1;
	}
	if(need < 0 || d > (n - 1) * n / 2) {puts("NO"); return;}
   	puts("YES");
	int now = 1;
	while(now <= n) _true[now] = 1, id[dep[now]] = now, now = now << 1;
	deepest = log2(n);
	for(int i = n; i >= 1 && need; --i) {
		if(_true[i]) continue;
		while(need) {
			--need;
			fa[i] = id[dep[i]], dep[i] = dep[fa[i]] + 1;
			if(dep[i] > deepest) {deepest = dep[i], id[dep[i]] = i; break;}
		}
		
		_true[i] = 1;
	}
	for(int i = 2; i <= n; ++i) write(fa[i]), putchar(' ');
	puts("");
}

signed main() {
	T = read();
	while(T--) {
		Run();
	}
	return 0;
}

显然, 这样达不到 \(O(n)\) 的效率, 观察可得, 我们其实不用一步步移, 如果能移到底端我们应该直接往下移, 否则扔到半路就可以结束了.

#include<cstdio>
#include<cmath>

#define Maxn 10000

using namespace std;

int T, n, d, fa[Maxn + 9], dep[Maxn + 9], id[Maxn + 9], deepest;
bool _true[Maxn + 9];

int read() {
	int sum = 0, f = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') sum = (sum << 3) + (sum << 1) + ch - '0', ch = getchar();
	return sum * f;
}

void write(int x) {
	if(x < 0) putchar('-'), write(-x);
	else if(x <= 9) putchar(x + '0');
	else write(x / 10), putchar(x % 10 + '0');
}

void Run() {
	n = read(), d = read();
	int need = d;
	for(int i = 1; i <= n; ++i) {
		_true[i] = 0;
		need -= dep[i];
		int leftson = i << 1, rightson = i << 1 | 1;
		if(leftson <= n) fa[leftson] = i, dep[leftson] = dep[i] + 1;
		if(rightson <= n) fa[rightson] = i, dep[rightson] = dep[i] + 1;
	}
	if(need < 0 || d > (n - 1) * n / 2) {puts("NO"); return;}
	puts("YES");
	int now = 1;
	while(now <= n) _true[now] = 1, id[dep[now]] = now, now = now << 1;
	deepest = log2(n);
	for(int i = n; i >= 1 && need; --i) {
		if(_true[i]) continue;
		int w = deepest + 1 - dep[i];
		if(w <= need) need -= w, fa[i] = id[deepest], ++deepest, id[deepest] = i, dep[i] = deepest;
		else fa[i] = id[dep[fa[i]] + need], need = 0, dep[i] += need;
		_true[i] = 1;
	}
	for(int i = 2; i <= n; ++i) write(fa[i]), putchar(' ');
	puts("");
}

signed main() {
	T = read();
	while(T--) {
		Run();
	}
	return 0;
}

标签:ch,int,题解,dep,while,Maxn,CF1311E,二叉树
From: https://www.cnblogs.com/TS357051/p/17087228.html

相关文章

  • [题解] P2685 [TJOI2012]桥 思路整理
    题目大意给一张\(n\)个点\(m\)条边的图,求删去一条边后最短路长度的最大值与对应删边方案数。思路首先考虑,如果删去的这条边不在原图最短路上,那么新图最短路长度与原......
  • 【题解】[FJOI2017]矩阵填数
    题目分析:最大值为\(v\)的限制显然可以转化为\(\lev\)的方案数减去\(\lev-1\)的方案数。因为这里有很多个这种限制所以直接容斥就好了,具体来说就是枚举哪些条件取......
  • 【题解】Luogu DTOI Round 4
    前言:好久不打洛谷的\(rated\)赛了,结果一打\(205,rk14\),看来是没有大佬来打。放一下链接:https://www.luogu.com.cn/contest/96429P8976「DTOI-4」排列题目分析:这个......
  • CF1037H Security题解
    根据字典序的定义,位置大的大于长度长的,长度长的大于长度短的。所以我们贪心,先追求长度长的,再追求后面的位置大的,再追求前面的位置大的。我们要一个能遍历子串的结构,就选......
  • 关于“等保保护”最常见问题解答!
    等保全称信息安全等级保护,它是网络安全体系中非常重要的组成部分。但很多人对等保不够了解,所以小编特整理了这篇文章,希望对你们有帮助。1、等级保护是强制性的吗?可......
  • 【题解】CF1770F Koxia and Sequence
    有没有觉得其他题解的模二Lucas逆用太智慧了,有没有觉得这题的第一思路是直接拆位算每一位是否有贡献,而不是先满足和的限制列式?这里提供另外一个做法。方向不同,结果一样......
  • Codeforces Round #848 (Div. 2) A~F 题解
    A.FlipFlopSum能换\(-1,-1\)就换,不能能换\(1,-1\)或\(-1,1\)也可以,否则只能换\(1,1\)。B.TheForbiddenPermutation如果原序列一开始就是好的那就结束,否则......
  • 关于github上README.md图片显示不出来的问题解决办法
    关于github上README.md图片显示不出来的问题解决办法出现原因:如果你的README文件内显示图片的路径是正确的,那么很有可能是因为DNS被污染了所以导致显示不正常,即无法访问存放......
  • 【PER #1】捉迷藏 / Ptz2022 Day1.Kyoto U L 题解
    今天心血来潮想改一改pj的题,发现了这场easyround的A还没改……跟自己和解了,想了两天没想明白,说说大致思路。题目链接只考虑一组询问怎么做,先把\(v\)当作根,称......
  • i.MX6ULL - 问题解决:NFS挂载失败 - VFS: Unable to mount root fs on unknown-block(2
    i.IMX6ULL-问题解决:NFS挂载失败-VFS:Unabletomountrootfsonunknown-block(2,0)开发环境:移植的linux5.4.7.0ubuntu1804x64arm-linux-gnueabihf-gccv7.5NFS方式......