2022省选前联考 AVL树/平衡树
题目描述
pks 得到了一棵 \(N\) 个节点,权值为 \(1\sim N\) 的 \(AVL\) 树,他觉得这棵树太大了,于是他想要删掉一些节点使得最后剩下的树恰好有 \(K\) 个节点。如果 pks 删掉了一个节点,那么以这个节点为根的整棵子树都会被删掉。最后剩下的树必须依旧是一棵 \(AVL\) 树。
pks 希望,留下的 \(K\) 个节点的中序遍历的字典序最小。他希望你能帮他找到这个方案,作为报答,他将会把自己的财富分一半给你。
第一行两个整数 \(N,K\),表示节点数量和要保留的节点数量。
接下来 \(N\) 行,每行一个数字 \(p_i\),表示权值为 \(i\) 的节点的父亲的权值,如果是 \(-1\) ,表示这个点是根节点。
一行,\(N\) 个字符,如果权值为 \(i\) 的节点留下来,则第 \(i\) 个字符为 \(1\),否则为 \(0\) 。
\(N \leq 5 \times 10 ^ 5\)
思路分析
考场只会写暴力
既然要求字典序最小的答案,一种很容易想到的贪心是枚举 \(1 \sim N\) 的节点,如果可以选择就把它加入最后的 \(AVL\) 树中去。但是我们应该如何判断呢?
这里给出一种思路,我们先假设当前节点已经选入 \(AVL\) 树中,再来求出如果它真的被我们选中的话一共至少要选多少个节点(\(AVL\) 树的高度差绝对值不超过一)。
我们可以用 \(dp\) 来解决这个问题。定义 \(f_{i,j}\) 表示以 \(i\) 为根节点,\(AVL\) 树的高度为 \(j\) 最少要选的个数。注意:\(j\) 的大小不应该大于 \(i\) 为根子树的高度大小
我们再从 \(AVL\) 树的定义出发,分别转移 :
- 左子树,右子树高度相等
- \(左子树高度 - 右子树高度 = 1\)
- \(右子树高度 - 左子树高度 = 1\)
这三种情况。
我们每次判断时都要从当前节点向上跳直到根节点,并且一路标号。
因为如果一个节点选择了,那么它的爸爸,爷爷,曾爷爷 ……一定必选。
每当我们路过一个节点时,我们都要临时更新当前节点的 \(f_{now,j}\) 数组。当选择失败时再还原即可。
#include <bits/stdc++.h>
#define file(a) freopen(a".in", "r", stdin), freopen(a".out", "w", stdout)
#define Enter putchar('\n')
#define quad putchar(' ')
namespace IO {
template <class T> inline void read(T &a);
template <class T, class ...rest> inline void read(T &a, rest &...x);
template <class T> inline void write(T x);
template <class T, class ...rest> inline void write(T x, rest ...a);
}
#define N 500005
#define int long long
int n, k, root, fa[N], rc[N], lc[N];
int f[N][30], dep[N], g[N][30], flag[N];
inline void update(int now) {
for (int i = 2; i <= dep[now]; i++) {
int min1, min2;
min1 = f[lc[now]][i - 1] + std::min(f[rc[now]][i - 1], f[rc[now]][i - 2]) + 1;
min2 = f[lc[now]][i - 2] + f[rc[now]][i - 1] + 1;
f[now][i] = std::min(min1, min2);
}
f[now][1] = f[now][0] = 0x3f3f3f3f;
}
inline void dfs(int now) {
if (now == 0) return ;
dfs(lc[now]); dfs(rc[now]);
dep[now] = std::max(dep[lc[now]], dep[rc[now]]) + 1;
update(now);
f[now][0] = 0, f[now][1] = 1;
}
inline bool check(int now) {
if (flag[now]) return true;
flag[now] ++;
for (int i = 0; i <= dep[now]; i++) g[now][i] = f[now][i];
f[now][0] = 0x3f3f3f3f;
while (now != root) {
now = fa[now];
for (int i = 0; i <= dep[now]; i++) g[now][i] = f[now][i];
update(now); flag[now] ++;
}
int minn = 0x3f3f3f3f;
for (int i = 1; i <= dep[root]; i++)
minn = std::min(minn, f[root][i]);
return minn <= k;
}
inline void CtrlZ(int now) {
flag[now] --;
for (int i = 0; i <= dep[now]; i++) f[now][i] = g[now][i];
while (now != root) {
now = fa[now];
for (int i = 0; i <= dep[now]; i++) f[now][i] = g[now][i];
flag[now] --;
}
}
signed main(void) {
// file("5071");
IO::read(n, k);
for (int i = 1, father; i <= n; i++) {
IO::read(father);
if (father == -1) root = i;
fa[i] = father;
if (lc[father] == 0) lc[father] = i;
else rc[father] = i;
}
memset(f, 0x3f, sizeof(f));
for (int i = 0; i <= n; i++) f[i][0] = 0;
dfs(root);
for (int i = 1; i <= n; i++) {
if (check(i)) printf("1");
else printf("0"), CtrlZ(i);
}
}
namespace IO {
template <class T> inline void read(T &a) {
T s = 0, t = 1;
char c = getchar();
while ((c < '0' || c > '9') && c != '-')
c = getchar();
if (c == '-')
c = getchar(), t = -1;
while (c >= '0' && c <= '9')
s = (s << 1) + (s << 3) + (c ^ 48), c = getchar();
a = s * t;
}
template <class T, class ...rest> inline void read(T &a, rest &...x) {
read(a); read(x...);
}
template <class T> inline void write(T x) {
if (x == 0) putchar('0');
if (x < 0) putchar('-'), x = -x;
int top = 0, sta[50] = {0};
while (x)
sta[++top] = x % 10, x /= 10;
while (top)
putchar(sta[top] + '0'), top --;
return ;
}
template <class T, class ...rest> inline void write(T x, rest ...a) {
write(x); quad; write(a...);
}
}
2022省选前联考 AVL树/平衡树的更多相关文章
- luoguP6623 [省选联考 2020 A 卷] 树(trie树)
luoguP6623 [省选联考 2020 A 卷] 树(trie树) Luogu 题外话: ...想不出来啥好说的了. 我认识的人基本都切这道题了. 就我只会10分暴力. 我是傻逼. 题解时间 先不 ...
- luoguP6624 [省选联考 2020 A 卷] 作业题(莫比乌斯反演,矩阵树定理)
luoguP6624 [省选联考 2020 A 卷] 作业题(莫比乌斯反演,矩阵树定理) Luogu 题外话: Day2一题没切. 我是傻逼. 题解时间 某种意义上说刻在DNA里的柿子,大概是很多人学 ...
- luoguP6619 [省选联考 2020 A/B 卷]冰火战士(线段树,二分)
luoguP6619 [省选联考 2020 A/B 卷]冰火战士(线段树,二分) Luogu 题外话1: LN四个人切D1T2却只有三个人切D1T1 很神必 我是傻逼. 题外话2: 1e6的数据直接i ...
- [十二省联考2019]异或粽子——可持久化trie树+堆
题目链接: [十二省联考2019]异或粽子 求前$k$大异或区间,可以发现$k$比较小,我们考虑找出每个区间. 为了快速得到一个区间的异或和,将原序列做前缀异或和. 对于每个点作为右端点时,我们维护出 ...
- [BZOJ 5252][LOJ 2478][九省联考2018] 林克卡特树
[BZOJ 5252][LOJ 2478][九省联考2018] 林克卡特树 题意 给定一个 \(n\) 个点边带权的无根树, 要求切断其中恰好 \(k\) 条边再连 \(k\) 条边权为 \(0\) ...
- LuoguP4383 [八省联考2018]林克卡特树lct
LuoguP4383 [八省联考2018]林克卡特树lct https://www.luogu.org/problemnew/show/P4383 分析: 题意等价于选择\(K\)条点不相交的链,使得 ...
- 题解 P6622 [省选联考 2020 A/B 卷] 信号传递
洛谷 P6622 [省选联考 2020 A/B 卷] 信号传递 题解 某次模拟赛的T2,考场上懒得想正解 (其实是不会QAQ), 打了个暴力就骗了\(30pts\) 就火速溜了,参考了一下某位强者的题 ...
- luoguP6622 [省选联考 2020 A/B 卷] 信号传递(状压dp)
luoguP6622 [省选联考 2020 A/B 卷] 信号传递(状压dp) Luogu 题外话: 我可能是傻逼, 但不管我是不是傻逼, 我永远单挑出题人. 题解时间 看数据范围可以确定状压dp. ...
- luoguP4383 [八省联考2018]林克卡特树(树上dp,wqs二分)
luoguP4383 [八省联考2018]林克卡特树(树上dp,wqs二分) Luogu 题解时间 $ k $ 条边权为 $ 0 $ 的边. 是的,边权为零. 转化成选正好 $ k+1 $ 条链. $ ...
随机推荐
- XCTF练习题---WEB---Training-WWW-Robots
XCTF练习题---WEB---Training-WWW-Robots flag:cyberpeace{e37180e3f5ad17b4ac71a131e2de1fcb} 解题步骤: 1.观察题目,打 ...
- XCTF练习题---MISC---embarrass
XCTF练习题---MISC---embarrass flag:flag{Good_b0y_W3ll_Done} 解题步骤: 1.观察题目,下载附件,这道题真难 2. 拿到手以后默认使用Wiresha ...
- Django安装+创建一个Django项目
安装 选用pycharm 在终端输入命令:pip install django 安装完成后创建项目 1.在你想创建项目的目录下输入下面的代码 2.django-admin startprojec ...
- 安装与基本配置DHCP服务器
一,安装DHCP服务器角色 1,打开[开始]→[管理工具]→[服务器管理器]→"仪表板"选项的[添加角色和功能],持续单机[下一步]按钮, 直至出现下图所示的"选择服务器 ...
- Python最强IDE(PyCharm)安装教程
欢迎关注公众号[Python开发实战],免费领取Python学习电子书! PyCharm是目前最流行.使用最广泛的Python IDE(Integrated Development Environme ...
- netty系列之:netty中常用的xml编码解码器
目录 简介 XmlFrameDecoder XmlDecoder 总结 简介 在json之前,xml是最常用的数据传输格式,虽然xml的冗余数据有点多,但是xml的结构简单清晰,至今仍然运用在程序中的 ...
- 【数据库】MYSQL如何添加索引
1.使用ALTER TABLE语句创建索性 应用于表创建完毕之后再添加. 1.1语法 ALTER TABLE 表名 ADD 索引类型 (unique,primary key,fulltext,inde ...
- Python数据分析--工具安装及Numpy介绍(1)
Anaconda 是一个跨平台的版本,通过命令行来管理安装包.进行大规模数据处理.预测分析和科学计算.它包括近 200 个工具包,大数据处理需要用到的常见包有 NumPy . SciPy . pand ...
- C# .NET ML.NET 机器学习 图像分类
一. 准备工作 IDE是 VS2019.先下载好"resnet_v2_50_299.meta"这个文件,放入"C:\Users\jk\AppData\Local\Temp ...
- 每日一题20180401-Linux
一.题目 1.1 在mysql命令行临时开启自动补全 1.2 通过shell脚本打印乘法口诀表 二.答案 2.1 # auto-rehash:读取表信息和列信息,可以在连上终端后开启tab补齐功能 # ...