BST,二叉排序树。这个东西应该算是联赛算法?然而我一直没有学orz。
于是我就调了一天。。真菜啊我
BST的原理很简单,保证中序遍历是有序的,我们称之为BST性质。
存储
为了方便之后的操作,这里我们用结构体来实现
struct node{
int son[2], fa, size, val; //son[0]为左儿子,son[1] 为右儿子
}a[100003];
遍历
inline void go(int k) {
if(a[k].son[0]) go(a[k].son[0]);
cout<<a[k].val<<" ";
if(a[k].son[1]) go(a[k].son[1]);
}
插入元素
然后考虑插入。实现起来也很简单,递归的一顿乱搞就可以。
inline void insert(int x, int k) {
if(cnt == 1) {
a[1].val = x;
a[1].size = 1;
a[1].fa = nil;
++cnt;
return;
}
if(x < a[k].val) {
if(!a[k].son[0]) {
a[k].son[0] = cnt;
a[cnt].fa = k;
a[cnt].val = x;
a[cnt].size = 1;
++cnt;
} else insert(x, a[k].son[0]);
} else {
if(!a[k].son[1]) {
a[k].son[1] = cnt;
a[cnt].fa = k;
a[cnt].val = x;
a[cnt].size = 1;
++cnt;
} else insert(x, a[k].son[1]);
}
update(k);
}
其中update操作用来更新大小
inline void update(int k) {
a[k].size = a[a[k].son[0]].size + a[a[k].son[1]].size + 1;
}
然后拿着这个模板可以去试着提交一下luogu1177快速排序,会T三个点,如果random_shuffle一下T两个。
姑且不论这些玄学问题,我们来看看其他操作。
查找一个数的位置
许多操作的基础。
同样递归的查找即可。
inline int find(int x, int k) {
if(a[k].val == x) return k;
if(x < a[k].val && a[k].son[0])
return find(x, a[k].son[0]);
if(x > a[k].val && a[k].son[1])
return find(x, a[k].son[1]);
return nil;
}
前驱
前驱就是中序遍历结果的前一个元素。
我们分类讨论一下:
如果有左子树,那么就是左子树的最大的元素也就是最右边的元素
如果没有左子树,是父亲的右子树,那么前驱是父亲。
如果没有左子树,是父亲的左子树,那么前驱就是一直找父亲直到某一个父亲是父亲的右子树。
放张图解释一下好了。
B的前驱是D
H的前驱是F,而E的前驱是B
G的前驱则是E,寻找过程是F->E为右子树
inline int prenode(int x) {
int k = find(x, 0);
if(k == nil) return nil;
if(a[k].son[0]) {
k = a[k].son[0];
while(a[k].son[1])
k = a[k].son[1];
return a[k].val;
}
while(a[k].fa != nil) {
if(a[a[k].fa].son[1] == k)
return a[a[k].fa].val;
k = a[k].fa;
}
return nil;
}
后继
后继就是中序遍历结果的后一个元素。
我们分类讨论一下:
如果有右子树,那么后继就是右子树最小的元素也就是最左的元素
如果没有右子树,是父亲的左子树,那么后继就是父亲
如果没有右子树,是父亲的右子树,那么后继就是一直找父亲直到某一个父亲是父亲的左子树。
inline int nxtnode(int x) {
int k = find(x, 1);
if(k == nil) return nil;
if(a[k].son[1]) {
k = a[k].son[1];
while(a[k].son[0]){
k = a[k].son[0];
}
return a[k].val;
}
while(a[k].fa != nil) {
if(a[a[k].fa].son[0] == k)
return a[a[k].fa].val;
k = a[k].fa;
}
return nil;
}
排名
排名指的是第几小(大),根据子树性质递归即可
inline int getrank(int x, int k, int ct) {
if(a[k].val == x) return (ct + a[a[k].son[0]].size + 1);
else if(a[k].son[0] && a[k].val > x)
return getrank(x, a[k].son[0], ct);
else if(a[k].son[1] && a[k].val < x)
return getrank(x, a[k].son[1], ct + a[a[k].son[0]].size + 1);
return nil;
}
k大
查找第k大的元素,如果在左子树就直接查找,否则对右子树查找k - a[a[k].son[0]].size - 1的元素
inline int getkth(int x, int k) {
if(x == a[a[k].son[0]].size + 1)
return a[k].val;
else if(a[k].son[0] && x <= a[a[k].son[0]].size)
return getkth(x, a[k].son[0]);
else if(a[k].son[1] && x >= a[a[k].son[0]].size + 2)
return getkth(x - a[a[k].son[0]].size - 1, a[k].son[1]);
}
删除
删除可能是最刺激的一个操作。因为二叉排序树的性质往往有牵一发而动全身的特性,所以(你懂得)
我们需要一个函数clear:
inline void clear(int k) {
a[k].son[0] = a[k].son[1] = a[k].fa = a[k].size = a[k].val = 0;
}
首先,如果左右儿子都没有,那就把父亲的儿子删掉之后直接clear掉。
其次,如果只有一个儿子,就嫡长子继承,把儿子搞上来即可。
最后,如果两个儿子,就找到后继。由于已经事先剔除了没有儿子的情况,所以后继人一定在儿子中,所以我们可以直接交换两者,并且对后继进行删除操作。
inline int erase(int x, int k) {
if(!a[k].son[0] && !a[k].son[1]) {
a[a[k].fa].son[a[a[k].fa].son[1] == k] = 0;
for(int i = a[k].fa; i != nil; i = a[i].fa)
--a[i].size;
clear(k);
}
else if(!a[k].son[0] || !a[k].son[1]) {
for(int i = a[k].fa; i != nil; i = a[i].fa)
--a[i].size;
int wson = (a[k].son[0] == 0), wk = a[k].son[wson];
a[a[k].fa].son[a[a[k].fa].son[1] == k] = wk;
a[a[k].son[wson]].fa = a[k].fa;
clear(k);
} else {
int tmpk = nxtnode(x);
a[k].val = a[tmpk].val;
erase(a[tmpk].val, tmpk);
}
}
完整代码
#include <bits/stdc++.h>
using namespace std;
#define nil 0x3fffff
int cnt = 1;
int qwq[100003];
struct node{
int son[2], fa, size, val;
}a[100003];
inline void read(int &x) {
x = 0; char c = getchar();
while(!isdigit(c)) c = getchar();
while(isdigit(c)) x = x * 10 + c - '0', c = getchar();
}
inline void update(int k) {
a[k].size = a[a[k].son[0]].size + a[a[k].son[1]].size + 1;
}
inline void insert(int x, int k) {
if(cnt == 1) {
a[1].val = x;
a[1].size = 1;
a[1].fa = nil;
++cnt;
return;
}
if(x < a[k].val) {
if(!a[k].son[0]) {
a[k].son[0] = cnt;
a[cnt].fa = k;
a[cnt].val = x;
a[cnt].size = 1;
++cnt;
} else insert(x, a[k].son[0]);
} else {
if(!a[k].son[1]) {
a[k].son[1] = cnt;
a[cnt].fa = k;
a[cnt].val = x;
a[cnt].size = 1;
++cnt;
} else insert(x, a[k].son[1]);
}
update(k);
}
inline void go(int k) {
if(a[k].son[0]) go(a[k].son[0]);
cout<<a[k].val<<" ";
if(a[k].son[1]) go(a[k].son[1]);
}
inline int find(int x, int k) {
if(a[k].val == x) return k;
if(x < a[k].val && a[k].son[0])
return find(x, a[k].son[0]);
if(x > a[k].val && a[k].son[1])
return find(x, a[k].son[1]);
return nil;
}
inline int prenode(int x) {
int k = find(x, 1);
if(k == nil) return nil;
if(a[k].son[0]) {
k = a[k].son[0];
while(a[k].son[1])
k = a[k].son[1];
return k;
}
while(a[k].fa != nil) {
if(a[a[k].fa].son[1] == k)
return a[k].fa;
k = a[k].fa;
}
return nil;
}
inline int nxtnode(int x) {
int k = find(x, 1);
if(k == nil) return nil;
if(a[k].son[1]) {
k = a[k].son[1];
while(a[k].son[0]){
k = a[k].son[0];
}
return k;
}
while(a[k].fa != nil) {
if(a[a[k].fa].son[0] == k)
return a[k].fa;
k = a[k].fa;
}
return nil;
}
inline int getrank(int x, int k, int ct) {
if(a[k].val == x) return (ct + a[a[k].son[0]].size + 1);
else if(a[k].son[0] && a[k].val > x)
return getrank(x, a[k].son[0], ct);
else if(a[k].son[1] && a[k].val < x)
return getrank(x, a[k].son[1], ct + a[a[k].son[0]].size + 1);
return nil;
}
inline int getkth(int x, int k) {
if(x == a[a[k].son[0]].size + 1)
return a[k].val;
else if(a[k].son[0] && x <= a[a[k].son[0]].size)
return getkth(x, a[k].son[0]);
else if(a[k].son[1] && x >= a[a[k].son[0]].size + 2)
return getkth(x - a[a[k].son[0]].size - 1, a[k].son[1]);
}
inline void clear(int k) {
a[k].son[0] = a[k].son[1] = a[k].fa = a[k].size = a[k].val = 0;
}
inline int erase(int x, int k) {
if(!a[k].son[0] && !a[k].son[1]) {
a[a[k].fa].son[a[a[k].fa].son[1] == k] = 0;
for(int i = a[k].fa; i != nil; i = a[i].fa)
--a[i].size;
clear(k);
}
else if(!a[k].son[0] || !a[k].son[1]) {
for(int i = a[k].fa; i != nil; i = a[i].fa)
--a[i].size;
int wson = (a[k].son[0] == 0), wk = a[k].son[wson];
a[a[k].fa].son[a[a[k].fa].son[1] == k] = wk;
a[a[k].son[wson]].fa = a[k].fa;
clear(k);
} else {
int tmpk = nxtnode(x);
a[k].val = a[tmpk].val;
erase(a[tmpk].val, tmpk);
}
}
int main() {
int n;
read(n);
int tmp;
for(int i = 0; i < n; ++i) {
read(qwq[i]);
}
for(int i = 0; i < n; ++i) insert(qwq[i], 1);
//go(1);
//cout<<endl;
//for(int i = 1; i < cnt; ++i) cout<<a[i].size<<" ";
//cout<<endl;
while(1) {
int cmd;
cin>>cmd;
int x;
if(cmd == 1) read(x), insert(x, 1);
if(cmd == 2) go(1), cout<<endl;
if(cmd == 3) read(x), cout<<find(x, 1)<<endl;
if(cmd == 4) read(x), cout<<a[prenode(x)].val<<endl;
if(cmd == 5) read(x), cout<<a[nxtnode(x)].val<<endl;
if(cmd == 6) read(x), cout<<getrank(x, 1, 0)<<endl;
if(cmd == 7) read(x), cout<<getkth(x, 1);
if(cmd == 8) read(x), erase(x, find(x, 1));
if(cmd == 9) break;
}
return 0;
}
/*
7
3 5 7 4 1 2 8
7
1 5 6 2 3 7 4
*/
怎么这么菜啊我