写在前面
参考资料&&orz gyh
嘤
博主是在\(gyh\)大佬的博客的帮助下,学会了\(\text{FHQ-Treap}\)咋么写的,博文链接如下
Luckyblock—FHQ-Treap
感谢\(gyh\)大佬,\(gyh\)永远滴神!
另外的参考资料
Shiina_Mashiro—平衡树(Splay、fhq Treap)
ctjcalc—【数据结构】FHQ Treap 详解
关于
\(\text{FHQ-Treap}\),又名无旋\(\text{Treap}\),是一种不需要旋转的平衡树(废话!),是由范浩强基于\(\text{Treap}\)发明的,以分裂、合并为核心操作,有码量小、易理解的优势,其操作方式使它天生支持维护序列、可持久化等特性。
直接上操作和代码吧,暂时还没有写操作的原理,以后会补
操作
核心操作
分裂
分裂分为按值分裂和按大小分裂两种,下面给出的代码是按值分裂
void split(int rt, int val, int &x, int &y) {
if (!rt) { x = y = 0; return; }
if (t[rt].val <= val) x = rt, split(t[rt].son[1], val, t[rt].son[1], y);
else y = rt, split(t[rt].son[0], val, x, t[rt].son[0]);
update(rt);
}
合并
int merge(int x, int y) {
if (!x || !y) return x + y;
if (t[x].ran < t[y].ran) {
t[x].son[1] = merge(t[x].son[1], y), update(x);
return x;
}
else {
t[y].son[0] = merge(x, t[y].son[0]), update(y);
return y;
}
}
其他操作
新建节点及更新
void update(int rt) {
t[rt].siz = t[t[rt].son[0]].siz + t[t[rt].son[1]].siz + 1;
}
int new_node(int val) {
t[++tot].val = val, t[tot].siz = 1, t[tot].ran = rand();
return tot;
}
插入节点
void insert(int val) {
split(root, val, X, Y);
root = merge(merge(X, new_node(val)), Y);
}
删除节点
void delte(int val) {
split(root, val, X, Z), split(X, val - 1, X, Y);
Y = merge(t[Y].son[0], t[Y].son[1]);
root = merge(merge(X, Y), Z);
}
查询值为val的数的排名
void rank(int val) {
split(root, val - 1, X, Y);
cout << t[X].siz + 1 << '\n';
root = merge(X, Y);
}
查询第k大值
int kth(int rt, int key) {
while (1) {
if (key <= t[t[rt].son[0]].siz) { rt = t[rt].son[0]; continue; }
if (key == t[t[rt].son[0]].siz + 1) return rt;
key -= t[t[rt].son[0]].siz + 1;
rt = t[rt].son[1];
}
}
查询前驱pre
void pre(int val) {
split(root, val - 1, X, Y);
cout << t[kth(X, t[X].siz)].val << '\n';
root = merge(X, Y);
}
查询后继suc
void suc(int val) {
split(root, val, X, Y);
cout << t[kth(Y, 1)].val << '\n';
root = merge(X, Y);
}
代码
本代码为洛谷 P3369 【模板】普通平衡树的代码
/*
Author:loceaner
*/
#include
#include
#include
#include
#include
using namespace std;
const int A = 5e5 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
inline int read() {
char c = getchar(); int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
int n, tot, root, X, Y, Z;
struct node { int son[2], siz, ran, val; } t[A];
void update(int rt) {
t[rt].siz = t[t[rt].son[0]].siz + t[t[rt].son[1]].siz + 1;
}
int new_node(int val) {
t[++tot].val = val, t[tot].siz = 1, t[tot].ran = rand();
return tot;
}
void split(int rt, int val, int &x, int &y) {
if (!rt) { x = y = 0; return; }
if (t[rt].val <= val) x = rt, split(t[rt].son[1], val, t[rt].son[1], y);
else y = rt, split(t[rt].son[0], val, x, t[rt].son[0]);
update(rt);
}
int merge(int x, int y) {
if (!x || !y) return x + y;
if (t[x].ran < t[y].ran) {
t[x].son[1] = merge(t[x].son[1], y), update(x);
return x;
}
else {
t[y].son[0] = merge(x, t[y].son[0]), update(y);
return y;
}
}
void insert(int val) {
split(root, val, X, Y);
root = merge(merge(X, new_node(val)), Y);
}
void delte(int val) {
split(root, val, X, Z), split(X, val - 1, X, Y);
Y = merge(t[Y].son[0], t[Y].son[1]);
root = merge(merge(X, Y), Z);
}
void rank(int val) {
split(root, val - 1, X, Y);
cout << t[X].siz + 1 << '\n';
root = merge(X, Y);
}
int kth(int rt, int key) {
while (1) {
if (key <= t[t[rt].son[0]].siz) { rt = t[rt].son[0]; continue; }
if (key == t[t[rt].son[0]].siz + 1) return rt;
key -= t[t[rt].son[0]].siz + 1;
rt = t[rt].son[1];
}
}
void pre(int val) {
split(root, val - 1, X, Y);
cout << t[kth(X, t[X].siz)].val << '\n';
root = merge(X, Y);
}
void suc(int val) {
split(root, val, X, Y);
cout << t[kth(Y, 1)].val << '\n';
root = merge(X, Y);
}
int main() {
n = read();
for (int i = 1, opt, x; i <= n; i++) {
opt = read(), x = read();
if (opt == 1) insert(x);
else if (opt == 2) delte(x);
else if (opt == 3) rank(x);
else if (opt == 4) cout << t[kth(root, x)].val << '\n';
else if (opt == 5) pre(x);
else if (opt == 6) suc(x);
}
return 0;
}