= Vain学习(C/C++ acm算法 python Linux Golang)的个人网站 =

Fhq treap

Posted on

传送门:

学了Fhq Treap之后,我深深的了解到 Fhq Treap的牛逼,因为上一张学了替罪羊平衡树,码量很大,操作繁琐,不支持提取区间信息,虽然简单理解,但是Fhq也很好理解呀,而且码量不大,能快速维护一颗平衡树,支持提取区间信息

Fhq Treap 的骚操作:

  • 分裂
  • 合并
  • 分裂:*

    分裂操作其实很简单理解,把一颗平衡树按照插入的值为界限,分裂成两棵树,记录两个树的根节点即可

合并:

合并的规则根据随机索引去合并二叉堆即可,这样这棵树就很难因为出题人造的数据而退化为一条链,除非运气十分的不好

参考代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#include <cstdio>
#include <algorithm>
#include <vector>
#include <iostream>
#include <map>
#include <queue>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
#include <set>
#include <random>
using namespace std;
const int inf = (1 << 30);
typedef long long ll;
const int maxn = 1e6 + 5;
vector<int> vec;
struct node
{
int ls, rs, w, key;
int sizx;
} tr[maxn * 32];
int cnt, rt;
int newnode(int w)
{
tr[++cnt].w = w, tr[cnt].key = rand();
tr[cnt].sizx = 1;
return cnt;
}
void pushup(int now)
{
tr[now].sizx = tr[tr[now].ls].sizx + tr[tr[now].rs].sizx + 1;
}
void split(int now, int w, int &x, int &y)
{
if (!now)
x = y = 0;
else
{
if (tr[now].w <= w)
{
x = now, split(tr[now].rs, w, tr[now].rs, y);
}
else
{
y = now, split(tr[now].ls, w, x, tr[now].ls);
}
pushup(now);
}
}
int merge(int x, int y)
{
if (!x || !y)
return x + y;
if (tr[x].key > tr[y].key)
{
tr[x].rs = merge(tr[x].rs, y);
pushup(x);
return x;
}
else
{
tr[y].ls = merge(x, tr[y].ls);
pushup(y);
return y;
}
}
int x, y, z;
void inser(int w)
{
split(rt, w, x, y);
rt = merge(merge(x, newnode(w)), y);
}
void dele(int w)
{
split(rt, w, x, z);
split(x, w - 1, x, y);
y = merge(tr[y].ls, tr[y].rs);
rt = merge(merge(x, y), z);
}
void getrank(int w)
{
split(rt, w - 1, x, y);
cout << tr[x].sizx + 1 << endl;
rt = merge(x, y);
}
void getnum(int rank)
{
int now = rt;
while (now)
{
if (tr[tr[now].ls].sizx + 1 == rank)
break;
else if (tr[tr[now].ls].sizx >= rank)
now = tr[now].ls;
else
{
rank -= tr[tr[now].ls].sizx + 1;
now = tr[now].rs;
}
}
cout << tr[now].w << endl;
}
void pre(int w)
{
split(rt, w - 1, x, y);
int now = x;
while (tr[now].rs)
now = tr[now].rs;
cout << tr[now].w << endl;
rt = merge(x, y);
}
void nxt(int w)
{
split(rt, w, x, y);
int now = y;
while (tr[now].ls)
now = tr[now].ls;
cout << tr[now].w << endl;
rt = merge(x, y);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin >> n;
while (n--)
{
int op, x;
cin >> op >> x;
switch (op)
{
case 1:
inser(x);
break;
case 2:
dele(x);
break;
case 3:
getrank(x);
break;
case 4:
getnum(x);
break;
case 5:
pre(x);
break;
case 6:
nxt(x);
break;
}
}
}