Splay

简介

毒瘤

模板

普通平衡树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#define lc T[i].ch[0]
#define rc T[i].ch[1]
struct Splay {
int v, sz, ch[2], cnt;
} T[maxn]; int top, rt, f[maxn];
inline int get(int i) { return i == T[f[i]].ch[1]; }
inline void clear(int i) { T[i].sz = T[i].v = lc = rc = T[i].cnt = f[i] = 0; }
void init_Splay() { for (int i = 1; i <= top; ++i) clear(i); rt = top = 0; }
inline int newnode(int v) {
int i = ++top;
T[i].cnt = T[i].sz = 1; T[i].v = v;
return i;
}
inline void update(int i) { T[i].sz = T[i].cnt + T[lc].sz + T[rc].sz; }
inline void rotate(int x) {
int fa = f[x], ffa = f[f[x]], wx = get(x);
f[x] = ffa; f[T[x].ch[wx ^ 1]] = fa; f[fa] = x;
if (ffa) T[ffa].ch[T[ffa].ch[1] == fa] = x;
T[fa].ch[wx] = T[x].ch[wx ^ 1]; T[x].ch[wx ^ 1] = fa;
update(fa); update(x);
}
void Splay(int i, int k = 0) {
for (int fa = f[i]; fa != k; rotate(i), fa = f[i])
if (f[fa] != k) rotate(get(i) == get(fa) ? fa : i);
if (!k) rt = i;
}
void insert(int v) {
int i = rt, d;
if (!i) return (void) (rt = newnode(v));
while (1) {
d = v > T[i].v;
if (T[i].v == v) return ++T[i].cnt, Splay(i);
if (!T[i].ch[d]) {
T[i].ch[d] = newnode(v); f[T[i].ch[d]] = i;
Splay(T[i].ch[d]); return ;
} i = T[i].ch[d];
}
}
int findk(int k) {
int i = rt;
while (1) {
if (k <= T[lc].sz) { i = lc; continue; }
k -= T[lc].sz;
if (k <= T[i].cnt) return Splay(i), i;
k -= T[i].cnt; i = rc;
}
}
int find(int v) { // 如果 v 存在,可以找到 v,否则找到大于 v 最小 或者 小于 v 最大
int i = rt;
while (T[i].ch[v > T[i].v] && v != T[i].v) i = T[i].ch[v > T[i].v];
Splay(i); return i;
}
int findp(int v) {
find(v); int i = T[rt].ch[0];
if (T[rt].v < v) return rt;
while (rc) i = rc; Splay(i); return i;
}
int findn(int v) {
find(v); int i = T[rt].ch[1];
if (T[rt].v > v) return rt;
while (lc) i = lc; Splay(i); return i;
}
void del(int v) { // 在保证前驱和后继都存在的情况下,删除权值为 v 的点
int pre = findp(v), nxt = findn(v), i;
Splay(pre); Splay(nxt, pre); i = T[nxt].ch[0];
if (T[i].cnt > 1) return --T[i].cnt, Splay(i);
T[nxt].ch[0] = 0; clear(i); update(nxt); update(pre);
}
void del() { // 在保证所删除点一定存在左儿子和右儿子的情况下,删除根
int i = T[rt].ch[0], o = rt;
while (rc) i = rc; Splay(rt, i);
T[i].ch[1] = T[o].ch[1]; f[T[o].ch[1]] = i; update(i);
clear(o);
}

区间平衡树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#define lc T[i].ch[0]
#define rc T[i].ch[1]
struct Splay {
int v, val, sz, ch[2]; bool rev;
} T[maxn]; int top, rt, f[maxn];
void init_Splay() { T[0].v = -1; }
inline void update(int i) { if (!i) return ; T[i].sz = 1 + T[lc].sz + T[rc].sz; }
inline void Update(int i) { if (!i) return ; swap(lc, rc); T[i].rev ^= 1; }
inline void pushdown(int i) {
bool &rev = T[i].rev; if (!rev) return ;
Update(lc); Update(rc); rev = 0;
}
inline int get(int i) { return i == T[f[i]].ch[1]; }
inline void rotate(int x) {
int fa = f[x], ffa = f[f[x]], wx = get(x);
f[x] = ffa; f[T[x].ch[wx ^ 1]] = fa; f[fa] = x;
if (ffa) T[ffa].ch[T[ffa].ch[1] == fa] = x;
T[fa].ch[wx] = T[x].ch[wx ^ 1]; T[x].ch[wx ^ 1] = fa;
update(fa); update(x);
}
void Splay(int i, int k = 0) {
for (int fa = f[i]; fa != k; rotate(i), fa = f[i])
if (f[fa] != k) rotate(get(i) == get(fa) ? fa : i);
if (!k) rt = i;
}
void build(int &i, int l, int r, int fa) {
if (l > r) return ; i = ++top;
int m = l + r >> 1;
build(lc, l, m - 1, i); build(rc, m + 1, r, i);
T[i].val = a[m], f[i] = fa, update(i);
}
int find(int k) {
int i = rt;
while (1) { pushdown(i);
if (k <= T[lc].sz) i = lc;
else {
k -= T[lc].sz + 1;
if (!k) return Splay(i), i;
i = rc;
}
}
}
int split(int x, int y) { // [x, y]
x = find(x), y = find(y + 2);
Splay(x), Splay(y, x);
return T[y].ch[0];
}

例题

Luogu P3391 【模板】文艺平衡树

Luogu P3369 【模板】普通平衡树

Luogu P3960 [NOIP2017 提高组] 列队

CF 38G Queue