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

替罪羊树模板

Posted on

替罪羊树入门:

以洛谷模板题为例:
普通平衡树

这题正解是替罪羊树,呢么什么是替罪羊树?
替罪羊树其实就是一颗平衡树,但是我们要如何去维护树的平衡呢?
俗话说,暴力即优雅,替罪羊树,是通过重新构造不平衡的子树来进行维护树的平衡的
替罪羊树的部分:

  • 插入操作:插入节点((检查树的平衡(不平衡,则重构树(中序遍历,分治重构树,),更新树的节点信息)))
  • 删除操作:删除节点((检查树的平衡(不平衡,则重构树(中序遍历,分治重构树,),更新树的节点信息)))

参考代码:

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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
#include <cstdio>
#include <algorithm>
#include <vector>
#include <iostream>
#include <map>
#include <queue>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
#include <set>
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;
bool exist;
int sizx, fact;
} tr[maxn];
int cnt, root;
void pushup(int now)//维护节点信息
{
tr[now].sizx = tr[tr[now].ls].sizx + tr[tr[now].rs].sizx + 1;
tr[now].fact = tr[tr[now].ls].fact + tr[tr[now].rs].fact + 1;
}
void newnode(int &now, int w)//开新点
{
now = ++cnt;
tr[now].w = w, tr[now].sizx = tr[now].fact = 1;
tr[now].exist = true;
}
bool judge(int now) //判断是否平衡
{
if (max(tr[tr[now].ls].sizx, tr[tr[now].rs].sizx) > tr[now].sizx * 0.75)
return true;
if ((tr[now].sizx - tr[now].fact) > tr[now].sizx * 0.3)
return true;
return false;
}
void mds(int now)//中序遍历
{
if (!now)
return;
mds(tr[now].ls);
if (tr[now].exist)
vec.push_back(now);
mds(tr[now].rs);
}
void cre(int L, int R, int &now)//构造标准平衡树
{
if (L == R)
{
now = vec[L];
tr[now].ls = tr[now].rs = 0;
tr[now].sizx = tr[now].fact = 1;
return;
}
int mid = L + R >> 1;
while (L < mid && tr[vec[mid]].w == tr[vec[mid - 1]].w)
mid--;
now = vec[mid];
if (L < mid)
cre(L, mid - 1, tr[now].ls);
else
tr[now].ls=0;
cre(mid + 1, R, tr[now].rs);
pushup(now);
}
void update(int now, int en)//维护父辈节点
{
if (!now)
return;
if (tr[now].w > tr[en].w)
update(tr[now].ls, en);
else
update(tr[now].rs, en);
tr[now].sizx = tr[tr[now].ls].sizx + tr[tr[now].rs].sizx + 1;
}
void rebuild(int &now)//重构树
{
vec.clear();
mds(now);
if (vec.empty())
{
now = 0;
return;
}
cre(0, vec.size() - 1, now);
}
void check(int &now, int en) //检查,并重构子树
{
if (now == en)
return;
if (judge(now))
{
rebuild(now);
update(root, now);
return;
}
if (tr[en].w < tr[now].w)
check(tr[now].ls, en);
else
check(tr[now].rs, en);
}
void inser(int &now, int w)//插入
{
if (!now)
{
newnode(now, w);
check(root, now);
return;
}
tr[now].sizx++, tr[now].fact++;
if (w < tr[now].w)
inser(tr[now].ls, w);
else
inser(tr[now].rs, w);
}
void del(int now, int w)//删除
{
if (tr[now].exist && tr[now].w == w)
{
tr[now].exist = false;
tr[now].fact--;
check(root, now);
return;
}
tr[now].fact--;
if (w < tr[now].w)
del(tr[now].ls, w);
else
del(tr[now].rs, w);
}
int getrank(int w)//求w的排名
{
int now = root, rank = 1;
while (now)
{
if (w <= tr[now].w)
now = tr[now].ls;
else
{

rank += tr[now].exist + tr[tr[now].ls].fact,now = tr[now].rs;
}
}
return rank;
}
int getnum(int rank)//求排名为rank的树数
{
int now = root;
while (now)
{
if (tr[now].exist&&tr[tr[now].ls].fact + tr[now].exist == rank)
break;
else if (rank <= tr[tr[now].ls].fact)
now = tr[now].ls;
else
{
rank-=tr[now].exist + tr[tr[now].ls].fact,now=tr[now].rs;
}
}
return tr[now].w;
}
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(root,x);
break;
case 2:
del(root,x);
break;
case 3:
cout<<getrank(x)<<endl;
break;
case 4:
cout<<getnum(x)<<endl;
break;
case 5:
cout<<getnum(getrank(x)-1)<<endl;
break;
case 6:
cout<<getnum(getrank(x+1))<<endl;
break;
}
}
}