题目描述

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. 详解javascript的eventloop(一)

    先看一段代码 console.log('Hi') setTimeOut(function cb1(){ console.log('cb1') },500) console.log('Bye') 第一步 ...

  2. Vue2响应式原理

    vue2响应式原理 vue的特性:数据驱动视图和双向数据绑定.vue官方文档也提供了响应式原理的解释: 深入响应式原理 Object.defineProperty() Object.definePro ...

  3. Day 005:PAT练习--1047. 编程团体赛(20)

    编程团体赛的规则为:每个参赛队由若干队员组成:所有队员独立比赛:参赛队的成绩为所有队员的成绩和:成绩最高的队获胜.现给定所有队员的比赛成绩,请你编写程序找出冠军队. 输入格式: 输入第一行给出一个正整 ...

  4. ceph日常运维管理

    点击关注上方"开源Linux", 后台回复"读书",有我为您特别筛选书籍资料~ 相关阅读: ceph分布式存储简介 常见问题 nearfull osd(s) o ...

  5. maccms10二开批量入库和资源打包

    批量入库 因为maccms自带的采集采集起来很慢,而且很多资源站的采集接口不能对内容排序,导致最旧的数据最后入库.用java写个采集程序,采集完入库的时候发现不能一次性入库多个数据,导致入库也很慢,所 ...

  6. 无线:PIN码

    PIN码(PIN1),全称Personal Identification Number.就是SIM卡的个人识别密码.手机的PIN码是保护SIM卡的一种安全措施,防止别人盗用SIM卡,如果启用了开机PI ...

  7. JavaScript数组操作常用方法

    @ 目录 数组基础遍历方法. for for of for in 数组的基础操作方法. push:尾部追加元素 pop:尾部移出元素 unshift:头部追加元素 shift:头部移出元素 splic ...

  8. 142_Power BI之同比预测

    博客:www.jiaopengzi.com 焦棚子的文章目录 请点击下载附件 一.背景 最近刚好在做一个简单同比预测的模型,预测方法很简单,就是累计同比预测,把MTD展示出来. [video widt ...

  9. 110_Power Pivot特殊结算日期及财年日期

    博客:www.jiaopengzi.com 焦棚子的文章目录 请点击下载附件 1.背景 前几天看到群里有朋友在搞特殊结算日期,主要不是按照正常日期里的整月,按照比如:上月21号至本月20号作为结算周期 ...

  10. 将CSV格式或者EXCEL格式的文件导入到HIVE数据仓库中

    学习内容:数据导入,要求将CSV格式或者EXCEL格式的文件导入到HIVE数据仓库中: ①hive建表:test1 create table test1 (InvoiceNo String, Stoc ...