平衡树小记
定义:\(u\) 的排名为中序遍历后 \(u\) 在第几个
求 rank,kth,pre,nxt 有统一写法
int kth(int rk){
int u = head;
while (u){
if (siz[ls[u]]+1 == rk) return u;
if (siz[ls[u]]+1 < rk){
rk -= siz[ls[u]]+1;
u = rs[u];
} else {
u = ls[u];
}
}
return 0;
}
int rank(int x){
int u = head, rk = 0;
while (u){
if (val[u] < x){
rk += siz[ls[u]]+1;
u = rs[u];
} else {
u = ls[u];
}
}
return rk+1;
}
int pre(int x){
int u = head, res = -INT_MAX;
while (u){
if (val[u] < x){
res = max(res,val[u]);
u = rs[u];
} else {
u = ls[u];
}
}
return res;
}
int nxt(int x){
int u = head, res = INT_MAX;
while (u){
if (val[u] > x){
res = min(res,val[u]);
u = ls[u];
} else {
u = rs[u];
}
}
return res;
}
FHQ Treap
和 Treap 一样,每个节点随机一个优先级,且每个点的优先级都是其子树中最大的
核心操作:merge 和 split
- merge 操作:合并两个平衡树,我们考虑按优先级合并,那么肯定是优先级大的作为当前的根,然后递归合并剩下的
int merge(int l,int r){
if (!l) return r;
if (!r) return l;
if (pty[l] > pty[r]){
// ls[l] 不变
rs[l] = merge(rs[l],r);
up(l);
return l;
} else {
// rs[r] 不变
ls[r] = merge(l,ls[r]);
up(r);
return r;
}
}
- split 操作:分裂出一个所有节点 键值/排名 \(\le x\) 的树,和一个所有节点 键值/排名 \(> x\) 的树
void split(int l,int r,int u,int num){
// l:当前左树的节点,r:当前右树的节点,u:当前原树的节点
if (!u){
ls[r] = rs[l] = 0;
return ;
}
if (val[u] <= num){
rs[l] = u;
//ls[l] 不用改,一定合法
split(u,r,rs[u],num);
//ls[u] 不用遍历,一定在左树
} else {
ls[r] = u;
split(l,u,ls[u],num);
}
up(u);
}

浙公网安备 33010602011771号