FHQ Treap
Posted Harris-H
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了FHQ Treap相关的知识,希望对你有一定的参考价值。
FHQ Treap
1.有旋Treap
一些数组定义
int sum,R,num[N],sz[N],son[N][2],rd[N];
s u m sum sum结点数
R R R根结点编号
n u m [ ] num[] num[]当前结点出现的次数(与该结点值相同的个数)
s z [ ] sz[] sz[]该结点的子树大小
s o n [ ] [ ] son[][] son[][]记录结点的左右儿子
r d [ ] rd[] rd[]该结点的随机值,用于维护二叉堆 H e a p Heap Heap.
向上合并更新父亲信息
il void re(int p){
sz[p]=sz[son[p][0]]+sz[son[p][1]]+num[p];
}
旋转维护Heap
il void rot(int &p,int d){
int k=son[p][d^1]; //左旋取儿子,右选取左儿子.
son[p][d^1]=son[p][d]; //更新根结点的左儿子右为k的左儿子
son[k][d]=p;//k的左儿子设为p
re(p),re(k),p=k;更新p,k信息,根更新为k.
}
- 插入
- 删除
- 根据值找排名
- 根据排名找值
- 前驱
- 后继
基本操作
void ins(int &p,int x){
if(!p){ //为空结点直接新建
p=++sum,sz[p]=num[p]=1;
v[p]=x,rd[p]=rand();return;
}
if(v[p]==x){ //重复 更新num,sz
num[p]++,sz[p]++;return;
}
int d=x>v[p]; //往子树插入
ins(son[p][d],x);
if(rd[p]<rd[son[p][d]]) rot(p,d^1); //维护Max Heap
re(p);
}
void del(int &p,int x){
if(!p) return; //为空直接返回
if(x!=v[p]) del(son[p][x>v[p]],x); //往子树找
else {
if(!son[p][0]&&!son[p][1]){ //叶子直接更新
num[p]--,sz[p]--;
if(!num[p]) p=0; //为空删除 p=0
}
else if(son[p][0]&&!son[p][1]){ //右旋找右子树
rot(p,1);
del(son[p][1],x);
}
else if(!son[p][0]&&son[p][1]){ //左旋找左子树
rot(p,0);
del(son[p][0],x);
}
else { //找到rd较大的往该子树找
int d=rd[son[p][0]]>rd[son[p][1]];
rot(p,d);del(son[p][d],x);
}
}
re(p);
}
int rk(int p,int x){
if (!p) return 0;
if (v[p]==x) return sz[son[p][0]]+1;
if (v[p]<x) return sz[son[p][0]]+num[p]+rk(son[p][1],x);
if (v[p]>x) return rk(son[p][0],x);
}
int find(int p,int x){
if (!p) return 0;
if (sz[son[p][0]]>=x) return find(son[p][0],x);
else if (sz[son[p][0]]+num[p]<x)
return find(son[p][1],x-num[p]-sz[son[p][0]]);
else return v[p];
}
int pre(int p,int x){
if (!p) return -inf;
if (v[p]>=x) return pre(son[p][0],x);
else return max(v[p],pre(son[p][1],x));
}
int suf(int p,int x){
if (!p) return inf;
if (v[p]<=x) return suf(son[p][1],x);
else return min(v[p],suf(son[p][0],x));
}
完整版
#define il inline
int sum,R,num[N],sz[N],son[N][2],rd[N],v[N];
il void re(int p){
sz[p]=sz[son[p][0]]+sz[son[p][1]]+num[p];
}
il void rot(int &p,int d){
int k=son[p][d^1];
son[p][d^1]=son[k][d];
son[k][d]=p;
re(p),re(k),p=k;
}
void ins(int &p,int x){
if(!p){
p=++sum,sz[p]=num[p]=1;
v[p]=x,rd[p]=rand();return;
}
if(v[p]==x){
num[p]++,sz[p]++;return;
}
int d=x>v[p];
ins(son[p][d],x);
if(rd[p]<rd[son[p][d]]) rot(p,d^1);
re(p);
}
void del(int &p,int x){
if(!p) return;
if(x!=v[p]) del(son[p][x>v[p]],x);
else {
if(!son[p][0]&&!son[p][1]){
num[p]--,sz[p]--;
if(!num[p]) p=0;
}
else if(son[p][0]&&!son[p][1]){
rot(p,1);
del(son[p][1],x);
}
else if(!son[p][0]&&son[p][1]){
rot(p,0);
del(son[p][0],x);
}
else {
int d=rd[son[p][0]]>rd[son[p][1]];
rot(p,d);del(son[p][d],x);
}
}
re(p);
}
int rk(int p,int x){
if (!p) return 0;
if (v[p]==x) return sz[son[p][0]]+1;
if (v[p]<x) return sz[son[p][0]]+num[p]+rk(son[p][1],x);
if (v[p]>x) return rk(son[p][0],x);
}
int find(int p,int x){
if (!p) return 0;
if (sz[son[p][0]]>=x) return find(son[p][0],x);
else if (sz[son[p][0]]+num[p]<x)
return find(son[p][1],x-num[p]-sz[son[p][0]]);
else return v[p];
}
int pre(int p,int x){
if (!p) return -inf;
if (v[p]>=x) return pre(son[p][0],x);
else return max(v[p],pre(son[p][1],x));
}
int suf(int p,int x){
if (!p) return inf;
if (v[p]<=x) return suf(son[p][1],x);
else return min(v[p],suf(son[p][0],x));
}
2.无旋FHQ Treap
按权值分裂
int R; //全局定义初始化为0
int w[N],rd[N],sz[N],son[N][2],cnt; //定义在结构体内
w [ ] w[] w[]结点权值
r d [ ] rd[] rd[]结点的修正值,维护堆
s z [ ] sz[] sz[]结点子树大小
s o n [ ] [ ] son[][] son[][]记录左右儿子
c n t cnt cnt结点总数
向上合并信息
inline void re(int x){sz[x]=sz[son[x][0]]+sz[son[x][1]]+1;}
创建新结点
inline int newnode(int x){w[++cnt]=x,sz[cnt]=1,rd[cnt]=rand();return cnt;}
分裂
void split(int i,int k,int &x,int &y){if(!i) {x=y=0;return;} //如果i为空 左右子树=0 返回
//w[i]<=k 把i丢进左子树 左子树的虚拟结点为右儿子,递归
if(w[i]<=k以上是关于FHQ Treap的主要内容,如果未能解决你的问题,请参考以下文章