题解 AVL 树
2024-08-29 02:03:37
Description
给出一个 \(n\) 个点的 AVL 树,求保留 \(k\) 个点使得字典序最小。
\(n\le 5\times 10^5\)
Solution
因为我很 sb ,所以只会 \(\Theta(n\log^2n)\)。
首先可以注意到的是,树高是 \(\Theta(\log n)\) 的,然后我们要让字典序最小的话,可以考虑一个点一个点加进入判断是否可以。
我们考虑设 \(f_{u,i}\) 表示以 \(u\) 为根的子树在当前已选的点的情况下保留深度为 \(i\) 的还需选的最小点数。那么对于我们当前考虑的点,如果已经加入的点数加上还需加入的最小点数 \(\le k\) 那么我们就可以加入这个点。
发现这个 \(f\) 每次会改变的只会有 \(\text{rt}\to u\) 这一条路径(\(u\) 是当前考虑的点),所以我们就可以做到 \(\Theta(n\log^2 n)\) 了。
Code
#include <bits/stdc++.h>
using namespace std;
#define Int register int
#define MAXN 500005
template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> inline void chkmax (T &a,T b){a = max (a,b);}
template <typename T> inline void chkmin (T &a,T b){a = min (a,b);}
int n,K,rt,num,ans[MAXN],ls[MAXN],rs[MAXN],h[MAXN],f[MAXN],hei[MAXN],dp[MAXN][25];
void dfs1 (int u){
if (ls[u]) dfs1 (ls[u]);
if (rs[u]) dfs1 (rs[u]);
hei[u] = max (hei[ls[u]],hei[rs[u]]) + 1;
}
int tot,pos[25],reh[25],sta[25][25];
void ins (int root,int x){
++ tot,pos[tot] = root,reh[tot] = h[root];
for (Int i = 0;i <= hei[root];++ i) sta[tot][i] = dp[root][i];
if (root == x){
h[x] = max (h[ls[x]],h[rs[x]]) + 1,memset (dp[x],0x3f,sizeof (dp[x]));
for (Int i = h[x];i <= hei[x];++ i)
chkmin (dp[x][i],dp[ls[x]][i - 1] + dp[rs[x]][i - 1]),
chkmin (dp[x][i],dp[ls[x]][i - 2] + dp[rs[x]][i - 1]),
chkmin (dp[x][i],dp[ls[x]][i - 1] + dp[rs[x]][i - 2]);
return ;
}
else{
if (x < root) ins (ls[root],x);else ins (rs[root],x);
h[root] = max (h[ls[root]],h[rs[root]]) + 1,memset (dp[root],0x3f,sizeof (dp[root]));
for (Int i = h[root];i <= hei[root];++ i)
chkmin (dp[root][i],dp[ls[root]][i - 1] + dp[rs[root]][i - 1] + (root > x)),
chkmin (dp[root][i],dp[ls[root]][i - 2] + dp[rs[root]][i - 1] + (root > x)),
chkmin (dp[root][i],dp[ls[root]][i - 1] + dp[rs[root]][i - 2] + (root > x));
}
}
signed main(){
freopen ("avl.in","r",stdin);
freopen ("avl.out","w",stdout);
read (n,K);
for (Int i = 1;i <= n;++ i){
int p;read (p);
if (p == -1) rt = i;
else if (i < p) ls[p] = i;
else rs[p] = i;
}
dfs1 (rt),f[1] = 1,f[2] = 2;
for (Int i = 3;i <= 25;++ i) f[i] = f[i - 1] + f[i - 2] + 1;
memset (dp,0x3f,sizeof (dp));
for (Int u = 0;u <= n;++ u)
for (Int i = 0;i <= hei[u];++ i) dp[u][i] = f[i];
for (Int i = 1;i <= n;++ i){
tot = 0,ins (rt,i);
if (num + 1 + dp[rt][h[rt]] > K){
for (Int i = 1;i <= tot;++ i){
int now = pos[i];
h[now] = reh[i];for (Int k = 0;k <= hei[now];++ k) dp[now][k] = sta[i][k];
}
}
else ans[i] = 1,num ++;
}
for (Int i = 1;i <= n;++ i) putchar (ans[i] + '0');putchar ('\n');
return 0;
}
最新文章
- 用Unity代码通过Xml配置生成GameObject之——前两天掉的坑
- 【UOJ #150】【NOIP 2015】运输计划
- SQL Server Transact-SQL 编程
- AlarmManager 实现闹钟的基本功能
- JS的Document属性和方法
- TMS320C54x系列DSP的CPU与外设&mdash;&mdash;第3章 存储器
- Excel常用函数大全
- Spring Richclient — 企业级富客户端开发框架介绍,第 1 部分
- C#多线程下载一个文件
- .NET技能分析
- 怎样制作PHP验证码?
- [转]CentOS Apache 性能调试!
- 学生管理系统_排序后通过name删除列表里的字典
- C#处理json实战
- python --- 二分查找算法
- Centos7 ssh配置RSA证书登录
- PHP操作redis详细讲解(转)
- numpy.random随机数生成
- SignalR简介
- python中执行shell命令行read结果
热门文章
- dpkg:处理 xxx (--configure)时出错解决办法,也可用于卸载软件出错的情况
- 三.Go微服务--令牌桶实现原理
- vue 之 后端返回空字符串用 null 和 “”以及 undefind 判断不到的问题
- Mac超好用的软件合集和系统设置
- SpringBoot详解(一)——
- Shell脚本一键部署——源码编译安装MySQL及自动补全工具
- 关于electron-vue打包后静态视频文件无法正常加载的问题解决方法
- BeanFactory和ApplicationContext对比
- 处理burp log 小脚本
- 利用GetInvalidFileNameChars()得到有效的文件名