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 $ 条链. $ ...
随机推荐
- AspNetCore配置多环境log4net配置文件
前言 在之前的文章中有讲到AspNetCore多环境配置文件的应用,我们根据自己多种环境分别配置多个appsettings.$EnvironmentName.json文件. 在实际的开发中我们可能会遇 ...
- 《手把手教你》系列基础篇(九十一)-java+ selenium自动化测试-框架设计基础-Logback实现日志输出-下篇(详解教程)
1.简介 为了方便查看和归档:(1)不同包的日志可能要放到不同的文件中,如service层和dao层的日志:(2)不同日志级别:调试.信息.警告和错误等也要分文件输出.所以宏哥今天主要介绍和分享的是: ...
- baiyang网站二代域名及短链接
http://985.so/wesv https://cloud.tencent.com/developer/column/93900
- JS 中 对象 基础认识
俗话说:"万物皆对象",在 Javascript 中除了原始值几乎所有的东西都可以看做对象: 布尔是对象( new 关键词定义) 数字是对象( new 关键词定义) 字符串是对象 ...
- C++学习笔记——多线程(1)
目前在做推理引擎开发相关的工作,这块内容的话,对工程能力的要求还是比较高的,不再像以前只是写一些Python脚本训训模型就可以了,而且深入了解C++之后,也能感受到Python较C++暴露出的缺点,另 ...
- 阿里新零售中的智能补货(I)— 库存模型
文章作者:阿里零售通算法团队 出品社区:DataFun 导读: 零售通作为阿里巴巴新零售的八路大军之一,肩负着"共建智能分销平台"和"让百万小店拥抱DT时代"的 ...
- 真香警告!JitPack 开源库集成平台
前言: 请各大网友尊重本人原创知识分享,谨记本人博客:南国以南i 简介 官方介绍: JitPack 是一个用于 JVM 和 Android 项目的新颖的包存储库.它按需构建 Git 项目并为您提供即用 ...
- 如何基于 ZEGO SDK 实现 Android 通话质量监测
功能简介 在进行视频通话过程中,用户有时候会出现网络不好的情况,比如在进行多人视频通话或者多人唱歌时,我们需要实时显示用户的网络质量. 示例源码 参考 下载示例源码 获取源码. 相关源码请查看 &qu ...
- mySql in 语句查询优化
有这么一条sql UPDATE product set BuyerCount =BuyerCount+1 where ProductId in( SELECT ProductId from order ...
- Linux嵌套目录权限的比较探究
在/tmp目录下新建一个嵌套目录,名字分别为test_0.test_1.test_2.在test_2目录下新建普通文件,名为tryme.设置test_0和test_2的权限为777,设置test_1的 ...