数据结构 — FHQ Treap
数据结构 — FHQ Treap
FHQ Treap 是啥呢?
FHQ Treap 据说是一个叫 fhq 的奆佬在考场上因为忘记算法而灵机一动创造出来的数据结构
treap = tree + heap ,就是同时拥有二叉搜索树和堆性质的一个数据结构。FHQ Treap 和 Splay 及其他树堆的区别就在于,没有乱七八糟的旋转操作
机制
FHQ Treap 就是一个平衡一点的二叉搜索树,而平衡则是通过定义一个随机 priority 使它满足堆性质保持的(并且由于堆和二叉搜索树的良好性质,treap 的子树也是一个合法的 treap )。所以,FHQ Treap 的各种操作都是平均 O(log n) 的
1 template<typename T,int maxsize> 2 class Treap 3 { 4 public: 5 Treap(){Seed=(int)(maxsize*999983ll%2147483647);clear();} 6 void clear() 7 { 8 Total=Root=0; 9 treap[0].Size=treap[0].Left=treap[0].Right=treap[0].Priority=0; 10 } 11 int create(T key)//initialize a node 12 { 13 int u=++Total; 14 treap[u].Size=1; 15 treap[u].Key=key; 16 treap[u].Left=treap[u].Right=0; 17 treap[u].Priority=Random(); 18 return u; 19 } 20 private: 21 struct Node 22 { 23 T Key; 24 int Left,Right,Size,Priority; 25 }treap[maxsize]; 26 int Seed,Total,Root; 27 int Random() 28 { 29 return Seed=(int)(Seed*943199ll%1000000007); 30 } 31 };
初始化大概就长这个样子(因为我不压行所以显得很长的亚子
下面就是 FHQ Treap 的重点了(敲黑板
FHQ Treap 的各种操作
Split
顾名思义,Split 就是把一个 treap 分成两个 treap 的操作。当然,新的 treap 也要有该满足的性质
Split 分为两种,一种是按照 size 分,一种是按照关键字分
void KeySplit(int u,T key,int &x,int &y)
把以结点 u 为根的 treap 按照关键字分成两个,储存在 x 和 y 里,x 里面关键字都小于等于 key ,y 里面都大于 key
对于结点 u ,若其关键字小于等于 key ,则根据二叉搜索树的性质,u 和 u 的左子树都应该属于 x ,不妨让 x 就等于 u ,x 的左子树就等于 u 的左子树(这样很方便的保证了 priority 满足堆的性质)。但是 x 的右子树是什么呢?我们可以发现,其实再把 u 的右子树按照 key 分成两个 treap ,小于等于 key 的那部分做 x 的右子树,大于 key 的那部分赋值给 y 即可。
u 的关键字大于 key 的情况,和上面的情形是对称的
注:代码里假设 0 为哨兵结点,即空结点
1 void KeySplit(int u,T key,int &x,int &y)//Split the treap by key 2 { 3 if(!u) 4 { 5 x=y=0; 6 return ; 7 } 8 if(treap[u].Key<=key) 9 { 10 x=u; 11 KeySplit(treap[u].Right,key,treap[u].Right,y); 12 } 13 else 14 { 15 y=u; 16 KeySplit(treap[u].Left,key,x,treap[u].Left); 17 } 18 pushup(u);//pushup(u)和线段树以及其他数据结构类似,用来更新当前结点关键字 19 }
void SizeSplit(int u,int Size,int &x,int &y)
按照大小分类和按照关键字分类的机制差不多,代码也和上面的类似
1 void SizeSplit(int u,int Size,int &x,int &y)//Split the treap by size 2 { 3 if(!u) 4 { 5 x=y=0; 6 return ; 7 } 8 if(treap[treap[u].Left].Size<Size) 9 { 10 x=u; 11 SizeSplit(treap[u].Right,Size-treap[treap[u].Left].Size-1,treap[u].Right,y);//一定不要忘了把左子树大小和根节点给减掉 12 } 13 else 14 { 15 y=u; 16 SizeSplit(treap[u].Left,Size,x,treap[u].Left); 17 } 18 pushup(u); 19 }
Merge
int merge(int x,int y)
将两个 treap 合成一个,返回根的结点序号
但是不是随便两个 treap 就能 merge 的,merge 要求 x 中所有结点 key 小于 y 中所有结点 key ,这样才能方便的保持二叉搜索树的性质
这时候,我们有两种 merge 方法都能满足二叉搜索树性质:把 y 合并到 x 右子树上 or 把 x 合并到 y 左子树上。考虑维护 priority 堆的性质,若 x 的优先级比 y 大,用第一种,反之,用第二种
1 int merge(int x,int y)//guarantee that : all key in x < all key in y 2 { 3 if(!x||!y)//这里处理 x,y 中有空结点的情形 4 return x+y; 5 if(treap[x].Priority>treap[y].Priority) 6 { 7 treap[x].Right=merge(treap[x].Right,y); 8 pushup(x); 9 return x; 10 } 11 else 12 { 13 treap[y].Left=merge(x,treap[y].Left); 14 pushup(y); 15 return y; 16 } 17 }
一些询问
Treap 的所有 query & modification 都是通过 split 和 merge 实现的
删除元素:将 treap 分为小于 key ,等于 key ,大于 key 三部分,用 1,3 两部分 merge 成新的 treap
添加元素:将 treap 分成小于、大于等于两部分,按序 merge 小于、新建的结点、大于等于
查找关键字排名:将 treap 分成小于、大于等于两部分,返回小于那部分大小 + 1
查找第 k 大:将 treap 按照 size 分成两部分,返回第二部分根节点
代码实现
1 template<typename T,int maxsize> 2 class Treap//FHQ Treap 3 { 4 public: 5 Treap(){Seed=(int)(maxsize*999983ll%2147483647);clear();} 6 void clear() 7 { 8 Total=Root=0; 9 treap[0].Size=treap[0].Left=treap[0].Right=treap[0].Priority=0; 10 } 11 int create(T key)//initialize a node 12 { 13 int u=++Total; 14 treap[u].Size=1; 15 treap[u].Key=key; 16 treap[u].Left=treap[u].Right=0; 17 treap[u].Priority=Random(); 18 return u; 19 } 20 void KeySplit(int u,T key,int &x,int &y)//Split the treap by key 21 { 22 if(!u) 23 { 24 x=y=0; 25 return ; 26 } 27 if(treap[u].Key<=key) 28 { 29 x=u; 30 KeySplit(treap[u].Right,key,treap[u].Right,y); 31 } 32 else 33 { 34 y=u; 35 KeySplit(treap[u].Left,key,x,treap[u].Left); 36 } 37 pushup(u); 38 } 39 void SizeSplit(int u,int Size,int &x,int &y)//Split the treap by size 40 { 41 if(!u) 42 { 43 x=y=0; 44 return ; 45 } 46 if(treap[treap[u].Left].Size<Size) 47 { 48 x=u; 49 SizeSplit(treap[u].Right,Size-treap[treap[u].Left].Size-1,treap[u].Right,y); 50 } 51 else 52 { 53 y=u; 54 SizeSplit(treap[u].Left,Size,x,treap[u].Left); 55 } 56 pushup(u); 57 } 58 int merge(int x,int y)//guarantee that : all key in x < all key in y 59 { 60 if(!x||!y) 61 return x+y; 62 if(treap[x].Priority>treap[y].Priority) 63 { 64 treap[x].Right=merge(treap[x].Right,y); 65 pushup(x); 66 return x; 67 } 68 else 69 { 70 treap[y].Left=merge(x,treap[y].Left); 71 pushup(y); 72 return y; 73 } 74 } 75 void insert(T key) 76 { 77 int a,b; 78 KeySplit(Root,key-1,a,b); 79 Root=merge(merge(a,create(key)),b); 80 } 81 void remove(T key) 82 { 83 int a,b,c; 84 KeySplit(Root,key,a,c); 85 KeySplit(a,key-1,a,b); 86 Root=merge(merge(a,merge(treap[b].Left,treap[b].Right)),c); 87 } 88 void removeAll(T key) 89 { 90 int a,b,c; 91 KeySplit(Root,key,a,c); 92 KeySplit(a,key-1,a,b); 93 Root=merge(a,c); 94 } 95 int rank(T key) 96 { 97 int a,b,ret; 98 KeySplit(Root,key-1,a,b); 99 ret=treap[a].Size+1; 100 Root=merge(a,b); 101 return ret; 102 } 103 T at(int r) 104 { 105 int u=Root; 106 while(true) 107 { 108 if(treap[treap[u].Left].Size+1==r) 109 break; 110 if(treap[treap[u].Left].Size+1<r) 111 { 112 r-=treap[treap[u].Left].Size+1; 113 u=treap[u].Right; 114 } 115 else 116 { 117 u=treap[u].Left; 118 } 119 } 120 return treap[u].Key; 121 } 122 T prev(T key) 123 { 124 int a,b; 125 T ret; 126 KeySplit(Root,key-1,a,b); 127 int u=a; 128 while(treap[u].Right) 129 u=treap[u].Right; 130 ret=treap[u].Key; 131 Root=merge(a,b); 132 return ret; 133 } 134 T next(T key) 135 { 136 int a,b; 137 T ret; 138 KeySplit(Root,key,a,b); 139 int u=b; 140 while(treap[u].Left) 141 u=treap[u].Left; 142 ret=treap[u].Key; 143 Root=merge(a,b); 144 return ret; 145 } 146 int size() 147 { 148 return treap[Root].Size; 149 } 150 private: 151 struct Node 152 { 153 T Key; 154 int Left,Right,Size,Priority; 155 }treap[maxsize]; 156 int Seed,Total,Root; 157 int Random() 158 { 159 return Seed=(int)(Seed*943199ll%1000000007); 160 } 161 void pushup(int u)//update the info of a node 162 { 163 if(u) 164 { 165 treap[u].Size=treap[treap[u].Left].Size+treap[treap[u].Right].Size+1; 166 } 167 } 168 };

浙公网安备 33010602011771号