$fhqTreap$
Posted colythme
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了$fhqTreap$相关的知识,希望对你有一定的参考价值。
- $fhqTreap$与$Treap$的差异
$fhqTreap$是$Treap$的非旋版本,可以实现一切$Treap$操作,及区间操作和可持久化
$fhqTreap$非旋关键在于分裂与合并$(Split & Merge)$
- $Split$
分裂相当于将一棵平衡树分为两棵平衡树,比如可以以值$x$为分界线,即分为一棵权值均$le x$的平衡树,及一棵权值均$> x$的平衡树
对于实现,有$A$树根$rtA$及$B$树根$rtB$,若当前结点$root$权值$le x$,则$root$左子树均属于$A$树,$>$同理
void Split (int root, int mid, int& rtA, int& rtB) { if (! root) { rtA = rtB = 0; return ; } if (Val[root] <= mid) rtA = root, Split (Son[root][1], mid, Son[root][1], rtB); else rtB = root, Split (Son[root][0], mid, rtA, Son[root][0]); update (root); }
- $Merge$
将两棵树合并为一棵,需要既满足$BST$亦满足$Heap$,又$A$树的权值均小于$B$树,所以$BST$性质很好满足,那么再判一下随机的$rank$大小就好了
如果$A$树结点$node_a$的$rank$小于$B$树的结点$node_b$的$rank$,那么$node_b$必然是$node_a$的右子节点,反之$node_a$必然是$node_b$的左子结点
int Merge (int rtA, int rtB) { if (! rtA || ! rtB) return rtA + rtB; if (Rank[rtA] < Rank[rtB]) { Son[rtA][1] = Merge (Son[rtA][1], rtB); update (rtA); return rtA; } else { Son[rtB][0] = Merge (rtA, Son[rtB][0]); update (rtB); return rtB; } }
- 单点操作
- $Insert$
将树以插入结点权值$x$分裂,在权值均$le x$的$A$树中插入即可
void Insert (int x) { int rtA, rtB; Split (Root, x, rtA, rtB); Root = Merge (Merge (rtA, newnode (x)), rtB); }
- $Delete$
将树以$x$分裂为$A$与$B$,再将$A$以$x - 1$为基准继续分裂为$C$与$D$,那么将$D$根节点的左右子节点合并即可
void Delete (int x) { int rtA, rtB, rtC; Split (Root, x, rtA, rtB); Split (rtA, x - 1, rtA, rtC); rtC = Merge (Son[rtC][0], Son[rtC][1]); Root = Merge (Merge (rtA, rtC), rtB); }
- $Query\_Rank$
int Query_Rank (int x) { int rtA, rtB; Split (Root, x - 1, rtA, rtB); int rank = Size[rtA] + 1; Root = Merge (rtA, rtB); return rank; }
- $Query\_Kth$
int Query_Kth (int root, int k) { while (true) { if (Size[Son[root][0]] >= k) root = Son[root][0]; else { k -= Size[Son[root][0]] + 1; if (! k) return Val[root]; root = Son[root][1]; } } }
- 前驱结点
将树以$x - 1$分裂,那么树$A$的最后一名即为该结点的前驱结点
int Query_Prenode (int x) { int rtA, rtB; Split (Root, x - 1, rtA, rtB); int pre = Query_Kth (rtA, Size[rtA]); Root = Merge (rtA, rtB); return pre; }
- 后继结点
int Query_Nextnode (int x) { int rtA, rtB; Split (Root, x, rtA, rtB); int nxt = Query_Kth (rtB, 1); Root = Merge (rtA, rtB); return nxt; }
- 完整代码
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <ctime> 5 #include <algorithm> 6 7 using namespace std; 8 9 const int MAXN = 1e05 + 10; 10 11 int Son[MAXN][2]= {0}; 12 int Size[MAXN]= {0}; 13 int Val[MAXN]= {0}; 14 int Rank[MAXN]= {0}; 15 int nodes = 0; 16 17 int Root = 0; 18 int newnode (int val) { 19 int root = ++ nodes; 20 Size[root] = 1; 21 Val[root] = val; 22 Rank[root] = rand (); 23 return root; 24 } 25 26 void update (int root) { 27 Size[root] = Size[Son[root][0]] + Size[Son[root][1]] + 1; 28 } 29 30 void Split (int root, int mid, int& rtA, int& rtB) { 31 if (! root) { 32 rtA = rtB = 0; 33 return ; 34 } 35 if (Val[root] <= mid) 36 rtA = root, Split (Son[root][1], mid, Son[root][1], rtB); 37 else 38 rtB = root, Split (Son[root][0], mid, rtA, Son[root][0]); 39 update (root); 40 } 41 42 int Merge (int rtA, int rtB) { 43 if (! rtA || ! rtB) 44 return rtA + rtB; 45 if (Rank[rtA] < Rank[rtB]) { 46 Son[rtA][1] = Merge (Son[rtA][1], rtB); 47 update (rtA); 48 return rtA; 49 } 50 else { 51 Son[rtB][0] = Merge (rtA, Son[rtB][0]); 52 update (rtB); 53 return rtB; 54 } 55 } 56 57 void Insert (int x) { 58 int rtA, rtB; 59 Split (Root, x, rtA, rtB); 60 Root = Merge (Merge (rtA, newnode (x)), rtB); 61 } 62 63 void Delete (int x) { 64 int rtA, rtB, rtC; 65 Split (Root, x, rtA, rtB); 66 Split (rtA, x - 1, rtA, rtC); 67 rtC = Merge (Son[rtC][0], Son[rtC][1]); 68 Root = Merge (Merge (rtA, rtC), rtB); 69 } 70 71 int Query_Rank (int x) { 72 int rtA, rtB; 73 Split (Root, x - 1, rtA, rtB); 74 int rank = Size[rtA] + 1; 75 Root = Merge (rtA, rtB); 76 return rank; 77 } 78 79 int Query_Kth (int root, int k) { 80 while (true) { 81 if (Size[Son[root][0]] >= k) 82 root = Son[root][0]; 83 else { 84 k -= Size[Son[root][0]] + 1; 85 if (! k) 86 return Val[root]; 87 root = Son[root][1]; 88 } 89 } 90 } 91 92 int Query_Prenode (int x) { 93 int rtA, rtB; 94 Split (Root, x - 1, rtA, rtB); 95 int pre = Query_Kth (rtA, Size[rtA]); 96 Root = Merge (rtA, rtB); 97 return pre; 98 } 99 100 int Query_Nextnode (int x) { 101 int rtA, rtB; 102 Split (Root, x, rtA, rtB); 103 int nxt = Query_Kth (rtB, 1); 104 Root = Merge (rtA, rtB); 105 return nxt; 106 } 107 108 int M; 109 110 int getnum () { 111 int num = 0; 112 char ch = getchar (); 113 int flag = 0; 114 115 while (! isdigit (ch)) { 116 if (ch == ‘-‘) 117 flag = 1; 118 ch = getchar (); 119 } 120 while (isdigit (ch)) 121 num = (num << 3) + (num << 1) + ch - ‘0‘, ch = getchar (); 122 123 return flag ? - num : num; 124 } 125 126 int main () { 127 // freopen ("Input.txt", "r", stdin); 128 129 srand (time (NULL)); 130 131 M = getnum (); 132 for (int Case = 1; Case <= M; Case ++) { 133 int opt = getnum (); 134 int x, k; 135 int rank, pre, nxt; 136 switch (opt) { 137 case 1: 138 x = getnum (); 139 Insert (x); 140 break; 141 case 2: 142 x = getnum (); 143 Delete (x); 144 break; 145 case 3: 146 x = getnum (); 147 rank = Query_Rank (x); 148 printf ("%d ", rank); 149 break; 150 case 4: 151 k = getnum (); 152 x = Query_Kth (Root, k); 153 printf ("%d ", x); 154 break; 155 case 5: 156 x = getnum (); 157 pre = Query_Prenode (x); 158 printf ("%d ", pre); 159 break; 160 case 6: 161 x = getnum (); 162 nxt = Query_Nextnode (x); 163 printf ("%d ", nxt); 164 break; 165 } 166 } 167 168 return 0; 169 } 170 171 /* 172 10 173 1 106465 174 4 1 175 1 317721 176 1 460929 177 1 644985 178 1 84185 179 1 89851 180 6 81968 181 1 492737 182 5 493598 183 */
- 区间操作
- 建树
类似线段树的建法即可
int Build (int left, int right) { if (left > right) return 0; int mid = (left + right) >> 1; int root = newnode (mid - 1); Son[root][0] = Build (left, mid - 1); Son[root][1] = Build (mid + 1, right); update (root); return root; }
- 区间操作
将树以$R$分裂,再将$A$树以$L - 1$分裂,那么得到的树$D$,就恰好包含了区间$[L, R]$,直接操作即可
int rtA, rtB; int rtC, rtD; Split (Root, R, rtA, rtB); Split (rtA, L - 1, rtC, rtD); // 以下为操作
- 完整代码
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <ctime> 5 #include <algorithm> 6 7 using namespace std; 8 9 const int MAXN = 1e05 + 10; 10 11 int Son[MAXN][2]= {0}; 12 int Size[MAXN]= {0}; 13 int Val[MAXN]= {0}; 14 int Rank[MAXN]= {0}; 15 int Revtag[MAXN]= {0}; 16 int nodes = 0; 17 18 int Root = 0; 19 int newnode (int x) { 20 int root = ++ nodes; 21 Size[root] = 1; 22 Val[root] = x; 23 Rank[root] = rand (); 24 Revtag[root] = 0; 25 return root; 26 } 27 28 void update (int root) { 29 Size[root] = Size[Son[root][0]] + Size[Son[root][1]] + 1; 30 } 31 32 int Build (int left, int right) { 33 if (left > right) 34 return 0; 35 int mid = (left + right) >> 1; 36 int root = newnode (mid - 1); 37 Son[root][0] = Build (left, mid - 1); 38 Son[root][1] = Build (mid + 1, right); 39 update (root); 40 return root; 41 } 42 43 void pushdown (int root) { 44 if (Revtag[root]) { 45 swap (Son[root][0], Son[root][1]); 46 Revtag[Son[root][0]] ^= 1; 47 Revtag[Son[root][1]] ^= 1; 48 Revtag[root] = 0; 49 } 50 } 51 52 void Split (int root, int mid, int& rtA, int& rtB) { 53 if (! root) { 54 rtA = rtB = 0; 55 return ; 56 } 57 pushdown (root); 58 if (Size[Son[root][0]] >= mid) 59 rtB = root, Split (Son[root][0], mid, rtA, Son[root][0]); 60 else 61 rtA = root, Split (Son[root][1], mid - Size[Son[root][0]] - 1, Son[root][1], rtB); 62 update (root); 63 } 64 65 int Merge (int rtA, int rtB) { 66 if (! rtA || ! rtB) 67 return rtA + rtB; 68 pushdown (rtA), pushdown (rtB); 69 if (Rank[rtA] < Rank[rtB]) { 70 Son[rtA][1] = Merge (Son[rtA][1], rtB); 71 update (rtA); 72 return rtA; 73 } 74 else { 75 Son[rtB][0] = Merge (rtA, Son[rtB][0]); 76 update (rtB); 77 return rtB; 78 } 79 } 80 81 void Reverse (int L, int R) { 82 int rtA, rtB; 83 int rtC, rtD; 84 Split (Root, R, rtA, rtB); 85 Split (rtA, L - 1, rtC, rtD); 86 Revtag[rtD] ^= 1; 87 rtA = Merge (rtC, rtD); 88 Root = Merge (rtA, rtB); 89 } 90 91 int N, M; 92 93 void Output (int root) { 94 pushdown (root); 95 if (Son[root][0]) 96 Output (Son[root][0]); 97 if (Val[root] >= 1 && Val[root] <= N) 98 printf ("%d ", Val[root]); 99 if (Son[root][1]) 100 Output (Son[root][1]); 101 } 102 103 int getnum () { 104 int num = 0; 105 char ch = getchar (); 106 107 while (! isdigit (ch)) 108 ch = getchar (); 109 while (isdigit (ch)) 110 num = (num << 3) + (num << 1) + ch - ‘0‘, ch = getchar (); 111 112 return num; 113 } 114 115 int main () { 116 srand (time (NULL)); 117 N = getnum (), M = getnum (); 118 Root = Build (1, N + 2); 119 for (int Case = 1; Case <= M; Case ++) { 120 int l = getnum (), r = getnum (); 121 l ++, r ++; 122 Reverse (l, r); 123 } 124 Output (Root); 125 puts (""); 126 127 return 0; 128 } 129 130 /* 131 5 1 132 1 3 133 */ 134 135 /* 136 5 3 137 1 3 138 1 3 139 1 4 140 */
- 可持久化
直接类似一般的可持久化实现,主要修改在$Split$与$Merge$操作
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <ctime> 5 #include <algorithm> 6 7 using namespace std; 8 9 const int MAXN = 5e05 + 10; 10 const int MAXLOG = 40 + 10; 11 12 int Son[MAXN * MAXLOG][2]= {0}; 13 int Size[MAXN * MAXLOG]= {0}; 14 int Val[MAXN * MAXLOG]= {0}; 15 int Rank[MAXN * MAXLOG]= {0}; 16 int nodes = 0; 17 18 int Root[MAXN]= {0}; 19 int newnode (int val) { 20 int root = ++ nodes; 21 Size[root] = 1; 22 Val[root] = val; 23 Rank[root] = rand (); 24 return root; 25 } 26 27 void update (int root) { 28 Size[root] = Size[Son[root][0]] + Size[Son[root][1]] + 1; 29 } 30 31 void copy (int pre, int p) { 32 Son[p][0] = Son[pre][0], Son[p][1] = Son[pre][1]; 33 Size[p] = Size[pre]; 34 Val[p] = Val[pre]; 35 Rank[p] = Rank[pre]; 36 } 37 38 void Split (int pre, int mid, int& rtA, int& rtB) { 39 if (! pre) { 40 rtA = rtB = 0; 41 return ; 42 } 43 if (Val[pre] <= mid) { 44 rtA = ++ nodes; 45 copy (pre, rtA); 46 Split (Son[pre][1], mid, Son[rtA][1], rtB); 47 update (rtA); 48 } 49 else { 50 rtB = ++ nodes; 51 copy (pre, rtB); 52 Split (Son[pre][0], mid, rtA, Son[rtB][0]); 53 update (rtB); 54 } 55 } 56 57 int Merge (int prertA, int prertB) { 58 if (! prertA || ! prertB) 59 return prertA + prertB; 60 if (Rank[prertA] < Rank[prertB]) { 61 int rtA = ++ nodes; 62 copy (prertA, rtA); 63 Son[rtA][1] = Merge (Son[prertA][1], prertB); 64 update (rtA); 65 return rtA; 66 } 67 else { 68 int rtB = ++ nodes; 69 copy (prertB, rtB); 70 Son[rtB][0] = Merge (prertA, Son[prertB][0]); 71 update (rtB); 72 return rtB; 73 } 74 } 75 76 void Insert (int& proot, int x) { 77 int rtA, rtB; 78 Split (proot, x, rtA, rtB); 79 proot = Merge (Merge (rtA, newnode (x)), rtB); 80 } 81 82 void Delete (int& proot, int x) { 83 int rtA, rtB, rtC; 84 Split (proot, x, rtA, rtB); 85 Split (rtA, x - 1, rtA, rtC); 86 rtC = Merge (Son[rtC][0], Son[rtC][1]); 87 proot = Merge (Merge (rtA, rtC), rtB); 88 } 89 90 int Query_Rank (int& proot, int x) { 91 int rtA, rtB; 92 Split (proot, x - 1, rtA, rtB); 93 int rank = Size[rtA] + 1; 94 proot = Merge (rtA, rtB); 95 return rank; 96 } 97 98 int Query_Kth (int root, int k) { 99 while (true) { 100 if (Size[Son[root][0]] >= k) 101 root = Son[root][0]; 102 else { 103 k -= Size[Son[root][0]] + 1; 104 if (! k) 105 return Val[root]; 106 root = Son[root][1]; 107 } 108 } 109 } 110 111 int Query_Prenode (int& proot, int x) { 112 int rtA = 0, rtB; 113 Split (proot, x - 1, rtA, rtB); 114 if (! rtA) 115 return - 2147483647; 116 int pre = Query_Kth (rtA, Size[rtA]); 117 proot = Merge (rtA, rtB); 118 return pre; 119 } 120 121 int Query_Nextnode (int& proot, int x) { 122 int rtA, rtB = 0; 123 Split (proot, x, rtA, rtB); 124 if (! rtB) 125 return 2147364847; 126 int nxt = Query_Kth (rtB, 1); 127 proot = Merge (rtA, rtB); 128 return nxt; 129 } 130 131 int M; 132 133 int getnum () { 134 int num = 0; 135 char ch = getchar (); 136 int flag = 0; 137 138 while (! isdigit (ch)) { 139 if (ch == ‘-‘) 140 flag = 1; 141 ch = getchar (); 142 } 143 while (isdigit (ch)) 144 num = (num << 3) + (num << 1) + ch - ‘0‘, ch = getchar (); 145 146 return flag ? - num : num; 147 } 148 149 int main () { 150 // freopen ("Input.txt", "r", stdin); 151 152 srand (time (NULL)); 153 M = getnum (); 154 for (int Case = 1; Case <= M; Case ++) { 155 Root[Case] = Root[getnum ()]; 156 int opt = getnum (); 157 int x, k; 158 int rank, pre, nxt; 159 switch (opt) { 160 case 1: 161 x = getnum (); 162 Insert (Root[Case], x); 163 break; 164 case 2: 165 x = getnum (); 166 Delete (Root[Case], x); 167 break; 168 case 3: 169 x = getnum (); 170 rank = Query_Rank (Root[Case], x); 171 printf ("%d ", rank); 172 break; 173 case 4: 174 k = getnum (); 175 x = Query_Kth (Root[Case], k); 176 printf ("%d ", x); 177 break; 178 case 5: 179 x = getnum (); 180 pre = Query_Prenode (Root[Case], x); 181 printf ("%d ", pre); 182 break; 183 case 6: 184 x = getnum (); 185 nxt = Query_Nextnode (Root[Case], x); 186 printf ("%d ", nxt); 187 break; 188 } 189 } 190 191 return 0; 192 } 193 194 /* 195 10 196 0 1 9 197 1 1 3 198 1 1 10 199 2 4 2 200 3 3 9 201 3 1 2 202 6 4 1 203 6 2 9 204 8 6 3 205 4 5 8 206 */
以上是关于$fhqTreap$的主要内容,如果未能解决你的问题,请参考以下文章