平衡树——替罪羊树
替罪羊树
一种不带旋转的平衡树,当不平衡时(一棵树不平衡就是这棵树的左子树或右子树上的节点总数大于这棵树的总节点数*平衡因子(0.7-0.8)),通过暴力重构的方式维护平衡。
对于替罪羊树上的每个节点需要存储:
1.节点的值。
2.节点的左右儿子节点。
3.删除标记(表示此节点是否被删除)。
4.以该节点为根节点的子树上的总节点数(含已删除和未删除)。
5.以该节点为根节点的子树上的未删除的节点数。
暴力重构
当需要将一棵不平衡的子树暴力重构时,需要先存下这棵子树的中序遍历序列(不含已被标记为删除的节点),然后取序列中心作为子树的根节点,并将序列分为两段序列,再重复第二种操作,最后就可以建成一棵平衡的子树。
这里还需要进行一种操作来方便后面的删除操作,就是如果设为根节点的节点与它在序列中的前一个位置的节点的值相等,则把根节点改为它在序列中的前一个节点,直到不相等或找到最头上。
插入
正常的二叉搜索树的插入,回溯时判断平衡,若不平衡则暴力重构。
删除
找到一个拥有与所要删除的值相等的值并未被标记为已删除的节点,将它标记为已删除。
否则,若要删的值小于目前所搜节点的值,搜左儿子,大于等于,搜右儿子(因为暴力重构中的操作将与根节点相等的节点放入了右子树中)。
代码
#include<iostream>
#include <cstdlib>
using namespace std;
int n;
struct node{
int l,r;
int sum;
int tre;
bool del;
int zhi;
}tree[100010];
int cnt=0;
int gen=0;
int a;
int dui[100010];
void pai(int u){
if(tree[u].l!=0){
pai(tree[u].l);
}
if(tree[u].del==0){
dui[++dui[0]]=u;
}
if(tree[u].r!=0){
pai(tree[u].r);
}
}
int cg(int l,int r){
if(l>r){
return 0;
}
if(l==r){
tree[dui[l]].sum=tree[dui[l]].tre=1;
tree[dui[l]].l=tree[dui[l]].r=0;
return dui[l];
}
int mid=(l+r)/2;
while(tree[dui[mid-1]].zhi==tree[dui[mid]].zhi&&mid>l){
mid--;
}
tree[dui[mid]].l=cg(l,mid-1);
tree[dui[mid]].r=cg(mid+1,r);
tree[dui[mid]].sum=tree[tree[dui[mid]].l].sum+tree[tree[dui[mid]].r].sum+1;
tree[dui[mid]].tre=tree[tree[dui[mid]].l].tre+tree[tree[dui[mid]].r].tre+(tree[dui[mid]].del==0);
return dui[mid];
}
int add(int u){
tree[u].sum++;
tree[u].tre++;
if(tree[u].zhi>tree[cnt].zhi){
if(tree[u].l==0){
tree[u].l=cnt;
return u;
}
tree[u].l=add(tree[u].l);
}
else{
if(tree[u].r==0){
tree[u].r=cnt;
return u;
}
tree[u].r=add(tree[u].r);
}
if(tree[u].tre*a/100<tree[tree[u].l].tre||tree[u].tre*a/100<tree[tree[u].r].tre){
dui[0]=0;
pai(u);
u=cg(1,dui[0]);
}
tree[u].sum=tree[tree[u].l].sum+tree[tree[u].r].sum+1;
tree[u].tre=tree[tree[u].l].tre+tree[tree[u].r].tre+(tree[u].del==0);
return u;
}
int del(int u,int x){
tree[u].tre--;
if(tree[u].zhi==x&&tree[u].del==0){
tree[u].del=1;
return u;
}
if(tree[u].zhi>x){
if(tree[u].l==0){
return u;
}
tree[u].l=del(tree[u].l,x);
}
else{
if(tree[u].r==0){
return u;
}
tree[u].r=del(tree[u].r,x);
}
if(tree[u].tre*a/100<tree[tree[u].l].tre||tree[u].tre*a/100<tree[tree[u].r].tre){
dui[0]=0;
pai(u);
u=cg(1,dui[0]);
}
tree[u].sum=tree[tree[u].l].sum+tree[tree[u].r].sum+1;
tree[u].tre=tree[tree[u].l].tre+tree[tree[u].r].tre+(tree[u].del==0);
return u;
}
int pm(int u,int x){
if(tree[u].zhi>=x){
if(tree[u].l==0){
return 0;
}
return pm(tree[u].l,x);
}
else{
if(tree[u].r==0){
return tree[tree[u].l].tre+(tree[u].del==0);
}
return tree[tree[u].l].tre+(tree[u].del==0)+pm(tree[u].r,x);
}
}
int shu(int u,int x){
if(tree[u].del==1){
if(x<=tree[tree[u].l].tre){
if(tree[u].l==0){
return 0;
}
return shu(tree[u].l,x);
}
else{
if(tree[u].r==0){
return 0;
}
return shu(tree[u].r,x-tree[tree[u].l].tre);
}
}
if(tree[tree[u].l].tre+1==x){
return tree[u].zhi;
}
if(tree[tree[u].l].tre>=x){
if(tree[u].l==0){
return 0;
}
return shu(tree[u].l,x);
}
if(tree[u].r==0){
return 0;
}
return shu(tree[u].r,x-tree[tree[u].l].tre-1);
}
int main(){
a=rand()%10+70;
cin>>n;
while(n--){
int opt,x;
cin>>opt>>x;
if(opt==1){
cnt++;
tree[cnt].zhi=x;
tree[cnt].sum=1;
tree[cnt].tre=1;
tree[cnt].del=0;
if(gen!=0){
gen=add(gen);
}
else{
gen=cnt;
}
}
if(opt==2){
gen=del(gen,x);
}
if(opt==3){
cout<<pm(gen,x)+1<<endl;
}
if(opt==4){
cout<<shu(gen,x)<<endl;
}
if(opt==5){
cout<<shu(gen,pm(gen,x))<<endl;
}
if(opt==6){
cout<<shu(gen,pm(gen,x+1)+1)<<endl;
}
}
return 0;
}