简介
FHQ Treap,又叫无旋 Treap,是一种平衡树,还可以支持可持久化,代码也通俗易懂。
例题
实现
每个节点需保存它所维护的值 val,它的子树大小 siz,父节点 fa 以及它的左儿子 lson 和右儿子 rson。
1 2 3 4 5
| struct tree { int val,pri,siz; tree *lson,*rson; }; tree nul{0,0,0,&nul,&nul},*root[N+1];
|
建立新节点
像 Treap 一样赋予随机值。
1 2 3 4 5 6
| inline tree *new_tree(int val) { tree *x=new tree; *x=tree{val,rand(),1,&nul,&nul}; return x; }
|
复制节点
1 2 3 4 5 6
| inline tree *copy(tree *ori) { tree *x=new tree; *x=*ori; return x; }
|
更新节点 siz
1 2 3 4 5
| inline void push_up(tree *x) { x->siz=x->lson->siz+x->rson->siz+1; return; }
|
合并
合并 x 和 y。(保证 x 的权值 ≤y 的权值)
如果两个节点中有空节点,则返回非空节点。
根据 Treap 的堆性质,选择随机值较大的点(假设是 x),合并它的右儿子(如果是 y 则为它的左儿子)与 y。
由于需要可持久化,需要重建 x 节点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| tree *merge(tree *x,tree *y) { if((x==&nul)||(y==&nul)) { return x==&nul?y:x; } if(x->pri<=y->pri) { y=copy(y); y->lson=merge(x,y->lson); push_up(y); return y; } else { x=copy(x); x->rson=merge(x->rson,y); push_up(x); return x; } }
|
分裂
将 x 分成权值 ≤val 的树和权值 >val 的树。
如果 x 的权值 ≤val,则把 x 的右儿子分裂,否则分裂左儿子。
注意可持久化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| void split(tree *x,int val,tree *&l,tree *&r) { if(x==&nul) { l=r=&nul; return; } if(x->val<=val) { l=copy(x); split(l->rson,val,l->rson,r); push_up(l); } else { r=copy(x); split(r->lson,val,l,r->lson); push_up(r); } return; }
|
插入值
将 root 分裂成分成权值 ≤val 的树 l 与权值 >val 的树 r。
新建一个值为 val 的节点(设为 x)。
依次合并 l,x,r 即可。
1 2 3 4 5 6 7 8
| void insert(tree *&root,int val) { tree *l,*r; split(root,val,l,r); tree *x=new_tree(val); root=merge(l,merge(x,r)); return; }
|
删除值
将 root 分裂成分成权值 <val 的树 l、权值 =val 的树 mid 与权值 >val 的树 r。
依次合并 l,lsonmid,rsonmid,r 即可。
1 2 3 4 5 6 7 8 9 10 11
| void del(tree *&root,int val) { tree *l,*l_mid,*mid,*r; split(root,val,l_mid,r); split(l_mid,val-1,l,mid); root=merge(l,merge(merge(mid->lson,mid->rson),r)); if(mid!=&nul) { delete mid; } return; }
|
查询排名为 rnk 的数
1 2 3 4 5 6 7 8
| int rnk2val(tree *x,int rnk) { if(rnk<=x->lson->siz) { return rnk2val(x->lson,rnk); } rnk-=x->lson->siz+1; return rnk?rnk2val(x->rson,rnk):x->val; }
|
查询 val 的排名
把 root 分裂为权值 <val 的树 l 与权值 ≥val 的树 r。
统计 sizl+1 即为答案。
1 2 3 4 5 6 7 8
| int val2rnk(tree *&root,int val) { tree *l,*mid_r; split(root,val-1,l,mid_r); int ret=l->siz+1; root=merge(l,mid_r); return ret; }
|
查询 val 的前驱
把 root 分裂为权值 <val 的树 l 与权值 ≥val 的树 r。
查询 l 中排名为 sizl 的数。
1 2 3 4 5 6 7 8 9 10 11
| int val2pre(tree *&root,int val) { tree *l,*r; split(root,val-1,l,r); if(l==&nul) { return -inf; } int ret=rnk2val(l,l->siz); root=merge(l,r); return ret; }
|
查询 val 的后继
把 root 分裂为权值 ≤val 的树 l 与权值 >val 的树 r。
查询 r 中最小的(排名为 1)的数。
1 2 3 4 5 6 7 8 9 10 11
| int val2suc(tree *&root,int val) { tree *l,*r; split(root,val,l,r); if(r==&nul) { return inf; } int ret=rnk2val(r,1); root=merge(l,r); return ret; }
|