5.17 普通平衡树
二叉查找树,左小右大,中序遍历是有序的(升序),快速查找插入删除某一个节点
视频
#include<bits/stdc++.h>
//节点信息的定义
//旋转操作,伸展操作
//查找操作
//插入,删除,查询
//O(logn)
using namespace std;
const int N = 100050;
struct node{
int s[2];//左右儿子
//s[0]左儿子,s[1]右儿子
int p;//父亲
int v;//节点权值
int cnt;//权值出现次数
int size;//子树大小
void init(int p1,int v1){
p=p1,v=v1;
cnt=size=1;
}
}tr[N];//
int root;//根节点编号
int idx;//节点个数
void pushup(int x){
tr[x].size=tr[tr[x].s[0]].size+tr[tr[x].s[1]].size+tr[x].cnt;
}
//保序且信息正确
void rotate(int x){
int y=tr[x].p,z=tr[y].p;
int k = tr[y].s[1]==x;
//k==1右;k==0左
tr[y].s[k]=tr[x].s[k^1];
tr[tr[x].s[k^1]].p=y;
tr[x].s[k^1]=y;
tr[y].p=x;
tr[z].s[tr[z].s[1]==y]=x;
tr[x].p=z;
pushup(y),pushup(x);
}
//伸展操作
//访问一个x,就把x旋转到根节点
//k>0,把x转到k下面;
//k=0,把x转到根
void splay(int x,int k){
while(tr[x].p!=k){
int y=tr[x].p,z=tr[y].p;
if(z!=k){
(tr[y].s[0]==x)^(tr[z].s[0]==y)?rotate(x):rotate(y);
}
rotate(x);
}
if(k==0)root=x;
}
void find(int v){//找到v并转到根
int x=root;
while(tr[x].s[v>tr[x].v]&&v!=tr[x].v){
x=tr[x].s[v>tr[x].v];
}
splay(x,0);
}
//找前驱,返回节点编号
int get_pre(int v){//前驱
find(v);
int x=root;
if(tr[x].v<v)return x;
x=tr[x].s[0];
while(tr[x].s[1]) x=tr[x].s[1];//左子树最大的
return x;
}
int get_suc(int v){
find(v);
int x=root;
if(tr[x].v>v)return x;
x=tr[x].s[1];
while(tr[x].s[0])x=tr[x].s[0];//右树最小的
return x;
}
//删除
void del(int v){
int pre=get_pre(v);
int suc=get_suc(v);
splay(pre,0),splay(suc,pre);
int del=tr[suc].s[0];
if(tr[del].cnt>1)tr[del].cnt--,splay(del,0);
else tr[suc].s[0]=0,splay(suc,0);
}
//排名
//查数v的排名
int get_rank(int v){
find(v);
return tr[tr[root].s[0]].size;
}
//数值
//查询排名是k的数值
int get_val(int k){
int x=root;
while(1){
int y=tr[x].s[0];
if(tr[y].size+tr[x].cnt<k){
k-=tr[y].size+tr[x].cnt;
x=tr[x].s[1];
}
else{
if(tr[y].size>=k)x=tr[x].s[0];
else break;
}
}
splay(x,0);
return tr[x].v;
}
//插入函数,插入v
void insert(int v){
int x=root,p=0;
while(x&&tr[x].v!=v)
p=x,x=tr[x].s[v>tr[x].v];
if(x) tr[x].cnt++;
else{
x=++idx;
tr[p].s[v>tr[p].v]=x;
tr[x].init(p,v);
}
splay(x,0);
}
int main(){
insert(-1e9);insert(1e9);
int n;
scanf("%d",&n);
int op,x;
while(n--){
scanf("%d%d",&op,&x);
if(op==1)insert(x);
if(op==2)del(x);
if(op==3)printf("%d\n",get_rank(x));
if(op==4)printf("%d\n",get_val(x+1));
if(op==5)printf("%d\n",tr[get_pre(x)].v);
if(op==6)printf("%d\n",tr[get_suc(x)].v);
}
return 0;
}
线段树套平衡树
线段树每个节点对应一个区间,在每个节点上构建一颗平衡树,维护该区间内的序列
平衡树可以使用splay