替罪羊树是一种没有旋转操作的二叉搜索树。
或者说就是一颗二叉搜索树,暴力的那种。
插入就是自上而下找到应该插入的地方而后插进去。
我们知道这样搞肯定是可以变成 O ( n ) O(n) O(n)的深度
其复杂度的保证依赖于重构。
即一棵子树不平衡直接提出来重构成完全二叉树。
不平衡的定义为:
m
a
x
(
s
i
z
[
x
0
]
,
s
i
z
[
x
1
]
)
>
s
i
z
[
x
]
∗
α
max(siz[x0],siz[x1])>siz[x]*\alpha
max(siz[x0],siz[x1])>siz[x]∗α
α
\alpha
α一般取
0.75
0.75
0.75
没有旋转的话删除会比较麻烦,需要找到左子树最右的点或右子树最左的点来替代,再把那个点删掉,所以这叫替罪羊树。
复杂度 O ( n l o g n ) O(nlogn) O(nlogn),天知道为什么
Code:
#include<cstdio>
#include<iostream>
#define al 0.75
#define x0 t[x][0]
#define x1 t[x][1]
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define max(a, b) ((a) > (b) ? (a) : (b))
using namespace std;
const int N = 1e5 + 5;
int Q, n, rt, op, x, t[N][2], siz[N], a[N], fa[N];
int d[N], d0;
int lr(int x) {return t[fa[x]][1] == x;}
void upd(int x) { siz[x] = siz[x0] + siz[x1] + 1;}
void ins(int &x, int k) {
if(!x) { x = k; return;}
int z = a[k] > a[x];
ins(t[x][z], k); fa[t[x][z]] = x;
upd(x);
}
int pd(int x) {return max(siz[x0], siz[x1]) > siz[x] * al;}
void rec(int x) {
if(!x) return;
rec(x0); d[++ d0] = x; rec(x1);
}
int dg(int l, int r) {
if(l > r) return 0;
int m = l + r >> 1, x = d[m];
fa[t[x][0] = dg(l, m - 1)] = x;
fa[t[x][1] = dg(m + 1, r)] = x;
upd(x); return x;
}
int ft(int x, int k) {return a[x] == k ? x : ft(t[x][k > a[x]], k);}
int fr(int x) { return x1 ? fr(x1) : x;}
int fl(int x) { return x0 ? fl(x0) : x;}
void del(int x) {
if(x0 && x1) {
int p = x0;
while(t[p][1]) p = t[p][1];
a[x] = a[p]; x = p;
}
int p = x0 ? x0 : x1, y = fa[x], z = lr(x);
fa[t[y][z] = p] = y;
for(x = y; x; x = fa[x]) upd(x);
if(x == rt) rt = p;
}
int gn(int x, int k) {
if(!x) return 0;
if(a[x] >= k) return gn(x0, k);
return siz[x0] + 1 + gn(x1, k);
}
int fn(int x, int k) {
if(siz[x0] + 1 == k) return x;
if(siz[x0] >= k) return fn(x0, k);
return fn(x1, k - siz[x0] - 1);
}
int gl(int x, int k) {
if(!x) return 0;
if(a[x] >= k) return gl(x0, k);
int p = gl(x1, k);
return p ? p : x;
}
int gr(int x, int k) {
if(!x) return 0;
if(a[x] <= k) return gr(x1, k);
int p = gr(x0, k);
return p ? p : x;
}
const int inf = 2147483647;
int main() {
freopen("a.in", "r", stdin);
freopen("a.out", "w", stdout);
cin >> Q;
a[++ n] = -inf; ins(rt, n);
a[++ n] = inf; ins(rt, n);
fo(ii, 1, Q) {
scanf("%d %d", &op, &x);
if(op == 1) {
a[++ n] = x; siz[n] = 1;
ins(rt, n);
int cur = 0;
x = n;
for(; x; x = fa[x]) if(pd(x)) cur = x;
if(cur) {
x = cur; d0 = 0, rec(x);
int y = fa[x], z = lr(x);
x = dg(1, d0);
fa[t[y][z] = x] = y;
if(rt == cur) rt = x;
}
}
if(op == 2) del(ft(rt, x));
if(op == 3) printf("%d\n", gn(rt, x));
if(op == 4) printf("%d\n", a[fn(rt, x + 1)]);
if(op == 5) printf("%d\n", a[gl(rt, x)]);
if(op == 6) printf("%d\n", a[gr(rt, x)]);
}
}