题目描述

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树/平衡树的更多相关文章

  1. luoguP6623 [省选联考 2020 A 卷] 树(trie树)

    luoguP6623 [省选联考 2020 A 卷] 树(trie树) Luogu 题外话: ...想不出来啥好说的了. 我认识的人基本都切这道题了. 就我只会10分暴力. 我是傻逼. 题解时间 先不 ...

  2. luoguP6624 [省选联考 2020 A 卷] 作业题(莫比乌斯反演,矩阵树定理)

    luoguP6624 [省选联考 2020 A 卷] 作业题(莫比乌斯反演,矩阵树定理) Luogu 题外话: Day2一题没切. 我是傻逼. 题解时间 某种意义上说刻在DNA里的柿子,大概是很多人学 ...

  3. luoguP6619 [省选联考 2020 A/B 卷]冰火战士(线段树,二分)

    luoguP6619 [省选联考 2020 A/B 卷]冰火战士(线段树,二分) Luogu 题外话1: LN四个人切D1T2却只有三个人切D1T1 很神必 我是傻逼. 题外话2: 1e6的数据直接i ...

  4. [十二省联考2019]异或粽子——可持久化trie树+堆

    题目链接: [十二省联考2019]异或粽子 求前$k$大异或区间,可以发现$k$比较小,我们考虑找出每个区间. 为了快速得到一个区间的异或和,将原序列做前缀异或和. 对于每个点作为右端点时,我们维护出 ...

  5. [BZOJ 5252][LOJ 2478][九省联考2018] 林克卡特树

    [BZOJ 5252][LOJ 2478][九省联考2018] 林克卡特树 题意 给定一个 \(n\) 个点边带权的无根树, 要求切断其中恰好 \(k\) 条边再连 \(k\) 条边权为 \(0\) ...

  6. LuoguP4383 [八省联考2018]林克卡特树lct

    LuoguP4383 [八省联考2018]林克卡特树lct https://www.luogu.org/problemnew/show/P4383 分析: 题意等价于选择\(K\)条点不相交的链,使得 ...

  7. 题解 P6622 [省选联考 2020 A/B 卷] 信号传递

    洛谷 P6622 [省选联考 2020 A/B 卷] 信号传递 题解 某次模拟赛的T2,考场上懒得想正解 (其实是不会QAQ), 打了个暴力就骗了\(30pts\) 就火速溜了,参考了一下某位强者的题 ...

  8. luoguP6622 [省选联考 2020 A/B 卷] 信号传递(状压dp)

    luoguP6622 [省选联考 2020 A/B 卷] 信号传递(状压dp) Luogu 题外话: 我可能是傻逼, 但不管我是不是傻逼, 我永远单挑出题人. 题解时间 看数据范围可以确定状压dp. ...

  9. luoguP4383 [八省联考2018]林克卡特树(树上dp,wqs二分)

    luoguP4383 [八省联考2018]林克卡特树(树上dp,wqs二分) Luogu 题解时间 $ k $ 条边权为 $ 0 $ 的边. 是的,边权为零. 转化成选正好 $ k+1 $ 条链. $ ...

随机推荐

  1. tomcat的搭建和介绍

    第19章 tomcat的搭建 19.1 tomcat学习之前的预备知识 19.1.1 什么是JVM和JDK,JRE JVM            java虚拟机,实现一份代码可以在不同的平台执行,具有 ...

  2. kubeadm 搭建 K8s

    kubeadm 搭建 K8s 本篇主要记录一下 使用 kubeadm 搭建 k8s 详细过程 ,环境使用 VirtualBox 构建的3台虚拟机 1.环境准备 操作系统:Centos7 (CentOS ...

  3. 前端架构三大巨头之一Angular | 深度讲解

    云智慧集团成立于2009年,是全栈智能业务运维解决方案服务商.经过多年自主研发,公司形成了从IT运维.电力运维到IoT运维的产业布局,覆盖ITOM.ITOA.ITSM.DevOps以及IoT几大领域, ...

  4. python @符号用法的简单理解

    一.用作函数修饰符 作用是为现有函数增加额外的功能,常用于插入日志.性能测试.事务处理等等 创建函数修饰符的规则:(1)修饰符是一个函数(2)修饰符取被修饰函数为参数(3)修饰符返回值取代被修饰函数 ...

  5. 编写引入svg

    SVG是一种XML语言,类似XHTML,可以用来绘制矢量图形,例如右面展示的图形.SVG可以通过定义必要的线和形状来创建一个图形,也可以修改已有的位图,或者将这两种方式结合起来创建图形.图形和其组成部 ...

  6. mysql中的date、datetime、timestamp你还不知道怎么使用吗

    在后端开发中经常会碰到涉及数据库的场景,不知道屏幕前的你有这样的疑惑没有,每每在遇到时间.日期字段总是让人头疼,分不清到底是选date还是datetime,亦或是timestamp,真是抓耳挠腮啊,怎 ...

  7. Docker中级篇,看这篇就对了

    点击上方"开源Linux",选择"设为星标"回复"学习"获取独家整理的学习资料! 姊妹篇: Docker容器网络-基础篇 十分钟看懂Dock ...

  8. Java学习笔记-基础语法Ⅷ-泛型、Map

    泛型 泛型本质上是参数化类型,也就是说所操作的数据类型被指定为一个参数,即将类型由原来的具体的类型参数化,然后在使用/调用时传入具体的类型,这种参数类型可以用在类.方法和接口中,分别为泛型类.泛型方法 ...

  9. MPLS基础与工作原理

    MPLS Fundamental History of WAN Protocol 1970年代之前 第一个 WAN 用于将办公室与终端连接到大型机和小型计算机系统. 它是从办公室到数据中心的点对点连接 ...

  10. 896.Montonic Array - LeetCode

    Question 896. Monotonic Array Solution 题目大意: 类似于数学中的减函数,增函数和物理中的加速度为正或为负 思路: 先比较前两个是大于0还是小于0,如果等于0就比 ...