定义

SBT也是一种自平衡二叉查找树,它的平衡原理是每棵树的大小不小于其兄弟树的子树的大小

即size(x->l)$\ge$size(x->r->l),size(x->r->r),右边同理size(x->r)$\ge$size(x->l->l),size(x->l->r)

具体操作

  旋转

    旋转几乎是所有平衡树所共有的操作,操作方法也基本相同

    

    

void rotate(SBT *&x,int d){//旋转操作,d=0表示左旋,d=1表示右旋
SBT *y=x->son[d^];//y指向要旋转到父节点的子节点
x->son[d^]=y->son[d],y->son[d]=x;//更新指向关系
y->size=x->size;//更新size值
x->size=size(x->son[])+size(x->son[])+x->num;
x=y;//别忘了将进入子树的指针指到y上
}

  平衡维护

    SBT的平衡维护是SBT所特有的操作,具体有两种情况(左右对称算一种)

      1.size(x->l)<size(x->r->r),即下图中的size(2)<size(7)

      

      这时我们只需要把3旋转到根即可

      

      这时size(7)>size(2),size(6),但size(6)不一定>size(4),size(5),所以要维护一下节点1,然后再维护一遍节点3

      2.size(x->l)<size(x->r->l),即下图中的size(2)<size(6)

      

      我们先把子树3右旋,6旋到3的位置

      

      这时size(2)还不一定大于size(3),size(8),于是我们把子树1左旋,将6变为根

      

      这时size(1)>size(9),size(7),但是子树1和3不一定平衡,所以平衡1,3,然后再平衡6

void maintain(SBT *&x,int d){//平衡操作,检查(x->son[d]的子树是否比x->son[d^1]大)
if(x->son[d]==NULL)return;
if(size(x->son[d^])<size(x->son[d]->son[d^]))rotate(x->son[d],d),rotate(x,d^);
else if(size(x->son[d^])<size(x->son[d]->son[d]))rotate(x,d^);
else return;
maintain(x->son[],),maintain(x->son[],),maintain(x,),maintain(x,);//平衡子树后再平衡一次x
}

   插入

      和二叉查找树的插入差不多,只是在插入后要平衡一下

void insert(SBT *&x,int key){
if(!x){x=new SBT(key);return;}
x->size++;
if(x->key==key){x->num++;return;}
int d=key>x->key;
insert(x->son[d],key);
maintain(x,d);//插入后平衡一遍
}

   删除

      如果要删除的节点有子节点为空,则用另一个子节点代替要删除的节点
      否则,用后继代替当前节点,然后递归删除后继

void del(SBT *&x,int key){
if(x->key!=key){
del(x->son[key>x->key],key);
x->size=size(x->son[])+size(x->son[])+x->num;
return;
}
x->size--;
if(x->num>){x->num--;return;}//num
SBT *p=x;
if(x->son[]==NULL)x=x->son[],delete p;
else if(x->son[]==NULL)x=x->son[],delete p;
else{//用后继替换当前节点,删除后继
p=x->son[];
while(p->son[]){
p=p->son[];
}
x->num=p->num,x->key=p->key,p->num=,del(x->son[],p->key);
}
}

其他操作

int query_id(SBT *x,int key){//求数列中比key小的有几个
if(!x)return ;
if(x->key>key)return query_id(x->son[],key);
if(x->key==key)return size(x->son[]);
return query_id(x->son[],key)+size(x->son[])+x->num;
}
int query_k(SBT *x,int k){//求排第k的数
if(!x)return ;
if(size(x->son[])>=k)return query_k(x->son[],k);
if(size(x->son[])+x->num>=k)return x->key;
return query_k(x->son[],k-size(x->son[])-x->num);
}
int ans;
void pre(SBT *x,int num){//求num的前驱(即小于num的最大的数),并存在ans里
if(!x)return;
if(x->key<num)ans=x->key,pre(x->son[],num);
else pre(x->son[],num);
}
void suc(SBT *x,int num){//求后继
if(!x)return;
if(x->key>num)ans=x->key,suc(x->son[],num);
else suc(x->son[],num);
}
void mid_traversal(SBT *x){//中序遍历
if(x->son[])mid_traversal(x->son[]);
printf("%d ",x->key);
if(x->son[])mid_traversal(x->son[]);
}

模板

#include<cstdio>
#include<cstring>
using namespace std;
#define size(x) (x?x->size:0)
struct SBT{
int key,size,num;
SBT *son[];
SBT(){
memset(this,,sizeof(SBT));
}
SBT(int x){
num=size=,key=x,son[]=son[]=;
}
}*root;
void rotate(SBT *&x,int d){//旋转操作,d=0表示左旋,d=1表示右旋
SBT *y=x->son[d^];//y指向要旋转到父节点的子节点
x->son[d^]=y->son[d],y->son[d]=x;//更新指向关系
y->size=x->size;//更新size值
x->size=size(x->son[])+size(x->son[])+x->num;
x=y;//别忘了将进入子树的指针指到y上
}
void maintain(SBT *&x,int d){//平衡操作,检查(x->son[d]的子树是否比x->son[d^1]大)
if(x->son[d]==NULL)return;
if(size(x->son[d^])<size(x->son[d]->son[d^]))rotate(x->son[d],d),rotate(x,d^);
else if(size(x->son[d^])<size(x->son[d]->son[d]))rotate(x,d^);
else return;
maintain(x->son[],),maintain(x->son[],),maintain(x,),maintain(x,);//平衡子树后再平衡一次x
}
void insert(SBT *&x,int key){
if(!x){x=new SBT(key);return;}
x->size++;
if(x->key==key){x->num++;return;}
int d=key>x->key;
insert(x->son[d],key);
maintain(x,d);//插入后平衡一遍
}
void del(SBT *&x,int key){
if(x->key!=key){
del(x->son[key>x->key],key);
x->size=size(x->son[])+size(x->son[])+x->num;
return;
}
x->size--;
if(x->num>){x->num--;return;}//num>1直接num-1即可
SBT *p=x;
if(x->son[]==NULL)x=x->son[],delete p;
else if(x->son[]==NULL)x=x->son[],delete p;
else{//用后继替换当前节点,删除后继
p=x->son[];
while(p->son[]){
p=p->son[];
}
x->num=p->num,x->key=p->key,p->num=,del(x->son[],p->key);
}
}
int query_id(SBT *x,int key){//求数列中比key小的有几个
if(!x)return ;
if(x->key>key)return query_id(x->son[],key);
if(x->key==key)return size(x->son[]);
return query_id(x->son[],key)+size(x->son[])+x->num;
}
int query_k(SBT *x,int k){//求排第k的数
if(!x)return ;
if(size(x->son[])>=k)return query_k(x->son[],k);
if(size(x->son[])+x->num>=k)return x->key;
return query_k(x->son[],k-size(x->son[])-x->num);
}
int ans;
void pre(SBT *x,int num){//求num的前驱(即小于num的最大的数),并存在ans里
if(!x)return;
if(x->key<num)ans=x->key,pre(x->son[],num);
else pre(x->son[],num);
}
void suc(SBT *x,int num){//求后继
if(!x)return;
if(x->key>num)ans=x->key,suc(x->son[],num);
else suc(x->son[],num);
}
void mid_traversal(SBT *x){//中序遍历
if(x->son[])mid_traversal(x->son[]);
printf("%d ",x->key);
if(x->son[])mid_traversal(x->son[]);
}
bool f=;
void check(SBT *x){
if(!x)return;
check(x->son[]);
check(x->son[]);
if(x->size!=size(x->son[])+size(x->son[])+)printf("woring");
}
int main(){
return ;
}

例题P3369 【模板】普通平衡树(Treap/SBT)

#include<cstdio>
#include<cstring>
using namespace std;
#define size(x) (x?x->size:0)
struct SBT{
int key,size,num;
SBT *son[];
SBT(){
memset(this,,sizeof(SBT));
}
SBT(int x){
num=size=,key=x,son[]=son[]=;
}
}*root;
void rotate(SBT *&x,int d){//旋转操作,d=0表示左旋,d=1表示右旋
SBT *y=x->son[d^];//y指向要旋转到父节点的子节点
x->son[d^]=y->son[d],y->son[d]=x;//更新指向关系
y->size=x->size;//更新size值
x->size=size(x->son[])+size(x->son[])+x->num;
x=y;//别忘了将进入子树的指针指到y上
}
void maintain(SBT *&x,int d){//平衡操作,检查(x->son[d]的子树是否比x->son[d^1]大)
if(x->son[d]==NULL)return;
if(size(x->son[d^])<size(x->son[d]->son[d^]))rotate(x->son[d],d),rotate(x,d^);
else if(size(x->son[d^])<size(x->son[d]->son[d]))rotate(x,d^);
else return;
maintain(x->son[],),maintain(x->son[],),maintain(x,),maintain(x,);//平衡子树后再平衡一次x
}
void insert(SBT *&x,int key){
if(!x){x=new SBT(key);return;}
x->size++;
if(x->key==key){x->num++;return;}
int d=key>x->key;
insert(x->son[d],key);
maintain(x,d);//插入后平衡一遍
}
void del(SBT *&x,int key){
if(x->key!=key){
del(x->son[key>x->key],key);
x->size=size(x->son[])+size(x->son[])+x->num;
return;
}
x->size--;
if(x->num>){x->num--;return;}//num>1直接num-1即可
SBT *p=x;
if(x->son[]==NULL)x=x->son[],delete p;
else if(x->son[]==NULL)x=x->son[],delete p;
else{//用后继替换当前节点,删除后继
p=x->son[];
while(p->son[]){
p=p->son[];
}
x->num=p->num,x->key=p->key,p->num=,del(x->son[],p->key);
}
}
int query_id(SBT *x,int key){//求数列中比key小的有几个
if(!x)return ;
if(x->key>key)return query_id(x->son[],key);
if(x->key==key)return size(x->son[]);
return query_id(x->son[],key)+size(x->son[])+x->num;
}
int query_k(SBT *x,int k){//求排第k的数
if(!x)return ;
if(size(x->son[])>=k)return query_k(x->son[],k);
if(size(x->son[])+x->num>=k)return x->key;
return query_k(x->son[],k-size(x->son[])-x->num);
}
int ans;
void pre(SBT *x,int num){//求num的前驱(即小于num的最大的数),并存在ans里
if(!x)return;
if(x->key<num)ans=x->key,pre(x->son[],num);
else pre(x->son[],num);
}
void suc(SBT *x,int num){//求后继
if(!x)return;
if(x->key>num)ans=x->key,suc(x->son[],num);
else suc(x->son[],num);
}
void mid_traversal(SBT *x){//中序遍历
if(x->son[])mid_traversal(x->son[]);
printf("%d ",x->key);
if(x->son[])mid_traversal(x->son[]);
}
bool f=;
void check(SBT *x){
if(!x)return;
check(x->son[]);
check(x->son[]);
if(x->size!=size(x->son[])+size(x->son[])+)printf("woring");
}
int main(){
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
int n,x,y;scanf("%d",&n);
while(n--){
scanf("%d%d",&x,&y);
switch(x){
case :
insert(root,y);
break;
case :
del(root,y);
break;
case :
printf("%d\n",query_id(root,y)+);
break;
case :
printf("%d\n",query_k(root,y));
break;
case :
pre(root,y);printf("%d\n",ans);
break;
default:
suc(root,y);printf("%d\n",ans); }
// mid_traversal(root);printf("\n");
}
return ;
}

Size Balanced Tree(节点大小平衡树)的更多相关文章

  1. Size Balanced Tree

    Size Balanced Tree(SBT)是目前速度最快的平衡二叉搜索树,且能够进行多种搜索操作,区间操作:和AVL.红黑树.伸展树.Treap类似,SBT也是通过对节点的旋转来维持树的平衡,而相 ...

  2. Size Balanced Tree(SBT) 模板

    首先是从二叉搜索树开始,一棵二叉搜索树的定义是: 1.这是一棵二叉树: 2.令x为二叉树中某个结点上表示的值,那么其左子树上所有结点的值都要不大于x,其右子树上所有结点的值都要不小于x. 由二叉搜索树 ...

  3. C基础 - 终结 Size Balanced Tree

    引言 - 初识 Size Balanced Tree 最近在抽细碎的时间看和学习 random 的 randnet 小型网络库. iamrandom/randnet - https://github. ...

  4. Size Balanced Tree(SBT树)整理

    不想用treap和Splay,那就用SB树把,哈哈,其实它一点也SB,厉害着呢. 先膜拜一下作者陈启峰.Orz 以下内容由我搜集整理得来. 一.BST及其局限性 二叉查找树(Binary Search ...

  5. 初学 Size Balanced Tree(bzoj3224 tyvj1728 普通平衡树)

    SBT(Size Balance Tree), 即一种通过子树大小(size)保持平衡的BST SBT的基本性质是:每个节点的size大小必须大于等于其兄弟的儿子的size大小: 当我们插入或者删除一 ...

  6. 手写一个节点大小平衡树(SBT)模板,留着用

    看了一下午,感觉有了些了解.应该没有错,有错希望斧正,感谢 #include<stdio.h> #include<string.h> struct s { int key,le ...

  7. 子树大小平衡树(Size Balanced Tree,SBT)操作模板及杂谈

    基础知识(包括但不限于:二叉查找树是啥,SBT又是啥反正又不能吃,平衡树怎么旋转,等等)在这里就不(lan)予(de)赘(duo)述(xie)了. 先贴代码(数组模拟): int seed; int ...

  8. Size Balance Tree(SBT模板整理)

    /* * tree[x].left 表示以 x 为节点的左儿子 * tree[x].right 表示以 x 为节点的右儿子 * tree[x].size 表示以 x 为根的节点的个数(大小) */ s ...

  9. 56. 2种方法判断二叉树是不是平衡二叉树[is balanced tree]

    [本文链接] http://www.cnblogs.com/hellogiser/p/is-balanced-tree.html [题目] 输入一棵二叉树的根结点,判断该树是不是平衡二叉树.如果某二叉 ...

随机推荐

  1. python爬取凤凰网站的新闻,及其链接地址,来源,时间和内容,用selenium自动化和requests处理数据

    有写规则需要自己定义判断. import requests from selenium import webdriver import time def grasp(urlT): driver = w ...

  2. CSDN的验证码,为什么要这样呢

    总是有连着的部分

  3. vue 计算属性实现过滤关键词

    效果 html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <m ...

  4. unity3d入门 Demo 学习记录

    闲来学习一下 unity3d 的Demo,记录如下. 官方 Demo,名字为 Roll-A-Ball,如图 场景比较简单,包含地面.玩家精灵.主摄像机.墙壁.可拾取的方块.分数为示 text.平行光源 ...

  5. Python基础知识之2——字典

    字典是什么? 字典是另外一个可变的数据结构,且可存储任意类型对象,比如字符串.数字.列表等.字典是由关键字和值两部分组成,也就是 key 和 value,中间用冒号分隔.这种结构类似于新华字典,字典中 ...

  6. System.UriFormatException: Invalid URI 解决方法

    mobox 企业网页登陆界面,sa 登陆后 提示 System.UriFormatException: Invalid URI: The URI scheme is not valid. at Sys ...

  7. js怎样把URL链接的参数截取出来

    有时候,A页面参数需要传递到B页面,则把参数拼接到跳转B页面的url上,这时怎样在另一个页面截取A页面传递的参数呢,主要代码如下 /** * 获取指定的URL参数值 URL:http://www.qu ...

  8. 中国剩余定理模数不互质的情况(poj 2891

    中国剩余定理模数不互质的情况主要有一个ax+by==k*gcd(a,b),注意一下倍数情况和最小 https://vjudge.net/problem/POJ-2891 #include <io ...

  9. configparser 配置文件模块

    #_author:star#date:2019/11/7# configparser 配置文件模块import configparserconfig=configparser.ConfigParser ...

  10. UITableViewCell delete button 上有其它覆盖层

    第一种解决办法: // Fix for iOS7, when backgroundView comes above "delete" button - (void)willTran ...