您的位置:首页 > 编程语言 > Qt开发

$fhqTreap$

2020-02-17 02:09 411 查看

- $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\n", rank);
149                 break;
150             case 4:
151                 k = getnum ();
152                 x = Query_Kth (Root, k);
153                 printf ("%d\n", x);
154                 break;
155             case 5:
156                 x = getnum ();
157                 pre = Query_Prenode (x);
158                 printf ("%d\n", pre);
159                 break;
160             case 6:
161                 x = getnum ();
162                 nxt = Query_Nextnode (x);
163                 printf ("%d\n", 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 */
fhqTreap

 

- 区间操作

  - 建树
    类似线段树的建法即可

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

[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\n", rank); 172 break; 173 case 4: 174 k = getnum (); 175 x = Query_Kth (Root[Case], k); 176 printf ("%d\n", x); 177 break; 178 case 5: 179 x = getnum (); 180 pre = Query_Prenode (Root[Case], x); 181 printf ("%d\n", pre); 182 break; 183 case 6: 184 x = getnum (); 185 nxt = Query_Nextnode (Root[Case], x); 186 printf ("%d\n", 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 */

可持久化平衡树 [p] 

转载于:https://www.cnblogs.com/Colythme/p/10008816.html

  • 点赞
  • 收藏
  • 分享
  • 文章举报
aigu1964 发布了0 篇原创文章 · 获赞 0 · 访问量 152 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: