FHQ treap学习(复习)笔记

.....好吧....最后一篇学习笔记的flag它倒了.....node

好吧,这篇笔记也鸽了很久很久了...c++

比赛前刷模板,才想着仍是补个坑吧...数据结构

FHQ,这个神仙(范浩强大佬),发明了这个神仙的数据结构,ide

首先,本篇博客使用洛谷普通平衡树为背景,即函数

  • 查找前驱
  • 查找后记
  • 查找kth的数
  • 查找k的排名
  • 插入一个数
  • 删除一个数

FHQ treap,是一个treap,它仍是和treap同样,是tree+heap,因此它也有一个键值维护堆的性质。学习

它能够干任何treap和Splay能干的事。spa

它的实现主要由两个函数实现:3d

merge:把两棵树合并成一棵code

split:把树分割成两棵blog

在这里介绍两个函数的实现方法:

merge

 

 

 

 

能够看到,它把两棵树合并了起来,可是并非简单地接起来,而是打散,从新组合。

代码:

int merge(int x,int y)//把xy为根的两棵子树给合并
{ if(!x||!y)//若是一边没了
    return x+y;//就返回
    if(t[x].key<t[y].key)//维护key值,若是x的key值小于y的k值
 { t[x].son[1]=merge(t[x].son[1],y);//说明此时必定不符合堆性质,把x的右儿子和y合并
        update(x);//更新相关变量
        return x;//返回根节点
 } else { t[y].son[0]=merge(x,t[y].son[0]);//同上
 update(y); return y; } }
View Code

经过这样一个递归,不断拆分节点&&合并的过程当中,就创建了一棵新树。

split:

 

从上图可得:(把树从5分开)

split的过程就是把树拆分红左右树,左树全部节点权值都小于k,右树的节点权值都大于k。

怎么实现呢?

代码:

void split(int now,int k,int &x,int &y)//把一棵树now给从k分割成x和y
{ if(!now) x=y=0;//若是没有了,就返回
    else { if(t[now].v<=k) //若是当前点的权值小于k,它应该在左子树
 { x=now;//更新
            split(t[now].son[1],k,t[now].son[1],y);分割右儿子,找一个可能的更大的 } else//同上
 { y=now; split(t[now].son[0],k,x,t[now].son[0]); } update(now); } }
View Code

这样,咱们就能够干以上的事了。

前置:查找kth

由于创建的事一个二叉查找树,因此仍是能够像遍历二叉查找树那样查找kth的。

代码十分简单

int kth(int now,int k) { while(1) { if(k<=t[t[now].son[0]].size) now=t[now].son[0]; else { if(k==t[t[now].son[0]].size+1) return now; else { k-=t[t[now].son[0]].size+1; now=t[now].son[1]; } } } }
View Code

而后就能够A掉普通平衡树了。

插入新节点:首先暴力新建一个节点

int new_node(int k) { tot++; t[tot].size=1; t[tot].v=k; t[tot].key=rand(); return tot; }
View Code

而后把树从k地方断开,把新节点看作一棵树,把它和上下树合在一块儿就好了

split(rt,a,x,y); rt=merge(merge(x,new_node(a)),y);
View Code

删除节点:

把树从k断开,而后把左树从k-1断开,而后把上下树给合并,把k节点扔了就好了

split(rt,a,x,z); split(x,a-1,x,y); y=merge(t[y].son[0],t[y].son[1]); rt=merge(merge(x,y),z);
View Code

查找排名:

把树从k分开,则k所在的数的size即便排名

split(rt,a-1,x,y); printf("%d\n",t[x].size+1); rt=merge(x,y);
View Code

查找kth:

直接用kth函数便可

printf("%d\n",t[kth(rt,a)].v);
View Code

前驱:

把树从k分开,则size-1大小的那个kth点就是前驱

split(rt,a-1,x,y); printf("%d\n",t[kth(x,t[x].size)].v); rt=merge(x,y);
View Code

后继:同上

split(rt,a,x,y); printf("%d\n",t[kth(y,1)].v); rt=merge(x,y);
View Code

完整高清无码代码:

#include<bits/stdc++.h>
using namespace std; const int maxn=1e6+10; struct tree { int son[2],v,key,size; }t[maxn]; int tot=0,rt=0; void update(int p) { t[p].size=t[t[p].son[0]].size+t[t[p].son[1]].size+1; } int new_node(int k) { tot++; t[tot].size=1; t[tot].v=k; t[tot].key=rand(); return tot; } int merge(int x,int y)//o?2¢ò?x£?y?a?ùμ?á???×óê÷
{ if(!x||!y) return x+y; if(t[x].key<t[y].key) { 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 split(int now,int k,int &x,int &y)//ò?è¨?μk·?à?nowê÷3éx,y 
{ if(!now) x=y=0; else { if(t[now].v<=k) //°??ùóDD?óúkμ?è¨?μμ??úμ?·?μ?ò???ê÷?D
 { x=now; split(t[now].son[1],k,t[now].son[1],y); } else { y=now; split(t[now].son[0],k,x,t[now].son[0]); } update(now); } } int kth(int now,int k) { while(1) { if(k<=t[t[now].son[0]].size) now=t[now].son[0]; else { if(k==t[t[now].son[0]].size+1) return now; else { k-=t[t[now].son[0]].size+1; now=t[now].son[1]; } } } } int x,y,z,n; int main() { srand((unsigned)time(NULL)); scanf("%d",&n); int flag,a,b,c; for(int i=1;i<=n;i++) { scanf("%d",&flag); scanf("%d",&a); if(flag==1) { split(rt,a,x,y); rt=merge(merge(x,new_node(a)),y); } if(flag==2) { split(rt,a,x,z); split(x,a-1,x,y); y=merge(t[y].son[0],t[y].son[1]); rt=merge(merge(x,y),z); } if(flag==3) { split(rt,a-1,x,y); printf("%d\n",t[x].size+1); rt=merge(x,y); } if(flag==4) { printf("%d\n",t[kth(rt,a)].v); } if(flag==5) { split(rt,a-1,x,y); printf("%d\n",t[kth(x,t[x].size)].v); rt=merge(x,y); } if(flag==6) { split(rt,a,x,y); printf("%d\n",t[kth(y,1)].v); rt=merge(x,y); } } return 0; }
相关文章
相关标签/搜索