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;
}