学习笔记(5)FHQ
又称“无旋 Treap”
主要通过分裂操作 \((split)\) 与合并操作 \((merge)\)维护 \(bst\) 的性质,在进行插入、删除、查询等操作时,通过权值分裂/排名分裂的方式将原平衡树分裂为 \(x\),\(y\) 两颗树进行操作(结合子树的 \(siz\)),后合并分裂的子树
例题
点击查看代码
#include <bits/stdc++.h>
#define N 100005
using namespace std;
inline int read(){
char ch = getchar(); int x = 0, f = 1;
while(!isdigit(ch)){if(ch == '-') f = -1; ch = getchar();}
while(isdigit(ch)){x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
return x * f;
}
int n;
struct Node{
int val, data, siz, cnt;
int son[2];
};
struct FHQ{
#define Lc(x) (t[x].son[0])
#define Rc(x) (t[x].son[1])
int tot, root, x, y, z;
Node t[N];
int add(int k){return t[++tot] = {k, rand(), 1}, tot;}
void pushup(int now){t[now].siz = 1 + t[Lc(now)].siz + t[Rc(now)].siz;}
void split(int now, int k, int &a, int &b){
if(!now){a = b = 0; return;}
if(k < t[now].val)
{b = now; split(Lc(now), k, a, Lc(now));}
else
{a = now; split(Rc(now), k, Rc(now), b);}
pushup(now);
}
int merge(int a, int b){
if(!a || !b) return a + b;
if(t[a].data <= t[b].data)
{Rc(a) = merge(Rc(a), b); pushup(a); return a;}
else
{Lc(b) = merge(a, Lc(b)); pushup(b); return b;}
}
int kth(int now, int k){
while(1){
if(k <= t[Lc(now)].siz) now = Lc(now);
else if(k -= t[Lc(now)].siz, k == 1) return now;
else --k, now = Rc(now);
}
}
void insert(int k){
split(root, k, x, y);
root = merge(merge(x, add(k)), y);
}
void remove(int k){
split(root, k, x, y);
split(x, k - 1, x, z);
z = merge(Lc(z), Rc(z));
root = merge(merge(x, z), y);
}
int get_rank(int k){
split(root, k - 1, x, y);
int res = t[x].siz + 1;
return root = merge(x, y), res;
}
int pre(int k){
split(root, k - 1, x, y);
int res = t[kth(x, t[x].siz)].val;
return root = merge(x, y), res;
}
int suf(int k){
split(root, k, x, y);
int res = t[kth(y, 1)].val;
return root = merge(x, y), res;
}
}T;
int main(){
// freopen(".in", "r", stdin);
// freopen(".out", "w", stdout);
n = read();
while(n--){
int opt = read(), x = read();
switch(opt){
case 1: T.insert(x); break;
case 2: T.remove(x); break;
case 3: printf("%d\n", T.get_rank(x)); break;
case 4: printf("%d\n", T.t[T.kth(T.root, x)].val); break;
case 5: printf("%d\n", T.pre(x)); break;
case 6: printf("%d\n", T.suf(x)); break;
}
}
return 0;
}