平衡树总结
结合pdf和 无旋Treap(FHQ Treap)理解吧,不想写了
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll cnt;//id
ll Root=0;//整颗树的根
struct tree{
ll lc,rc,val,siz,rk,lz;
}tr[1000000];
void pushup(ll root){//重新统计大小
tr[root].siz=tr[tr[root].lc].siz+tr[tr[root].rc].siz+1;
}
ll creat_in(ll x){//新建一个值为x的节点,并且返回ID
ll root=++cnt;
tr[root].siz=1;
tr[root].val=x;
tr[root].lc=tr[root].rc=0;
tr[root].rk=rand();
return root;
}
void split(ll root,ll z,ll &x,ll &y){// 到了一个结点root。x,y即分裂出的两个树
if(root==0){
x=y=0;
return;
}
if(tr[root].val<=z){
x=root;
split(tr[root].rc,z,tr[root].rc,y);
/*
tr[root].val <= z:当前节点的值小于等于分裂值
x = root:当前节点及其左子树肯定都属于x树
但右子树中可能既有≤z的也有>z的节点
split(tr[root].rc, z, tr[root].rc, y):
对右子树继续分裂
分裂后:tr[root].rc 接收所有≤z的部分,y 接收所有>z的部分
这样当前节点的右指针就指向了右子树中≤z的部分
*/
pushup(root);
}
else{
//同理
y=root;
split(tr[root].lc,z,x,tr[root].lc);
pushup(root);
}
}
ll merge(ll x,ll y){//合并X和Y,并且x和y分别为它们的根,并返回合并后的根
//第一棵树的所有节点值 都小于等于第二棵树
if(x==0||y==0){//任意一个为空,都不用做了
return x+y;
}
if(tr[x].rk>tr[y].rk){//x的优先级更高,x当根节点
tr[x].rc=merge(tr[x].rc,y);
pushup(x);
return x;
}
else{
tr[y].lc=merge(x,tr[y].lc);
pushup(y);
return y;
}
}
void insert(ll z){
//假设插入的值为key,把树分裂按key−1分裂成两棵,在中间新建结点,合并。
ll x,y;
split(Root,z-1,x,y);
Root=merge(merge(x,creat_in(z)),y);
return;
}
void remove(ll Z){//删除某个值
//假设删除的值为 key,将树按 key 分裂为 X 和 Z,再将 X 按 key - 1 分裂为 X 和 Y。
//此时 Y 中所有结点的值均等于 key。若仅删除一个结点,则将 Y 更新为其左右子树合并后的结果,最后合并 X、Y 和 Z;
//若需删除所有相应结点,则直接合并 X 和 Z。
ll x,y,z;
split(Root,Z,x,z);
split(x,Z-1,x,y);
if(y){
y=merge(tr[y].lc,tr[y].rc);
//目的:删除 y 树的根节点(即一个值为 key 的节点)
//方法:将 y 的左右子树合并,相当于"跳过"了根节点
}
Root=merge(merge(x,y),z);
}
ll get_rank(ll z){//查询指定值的排名
ll x,y,ans=0;
split(Root,z-1,x,y);
ans=tr[x].siz+1;
Root=merge(x,y);
return ans;
}
ll pm(ll z){//查询指定排名的值
if(z<1||z>tr[Root].siz) return -1e18;
ll root=Root;
while(1){
if(tr[tr[root].lc].siz+1==z){
break;
}
else if(tr[tr[root].lc].siz+1>z){
root=tr[root].lc;
}
else{
z-=tr[tr[root].lc].siz+1;
root=tr[root].rc;
}
}
return tr[root].val;
}
ll prev(ll z){//查找前驱
ll x,y,root;
ll ans=0;
split(Root,z-1,x,y);
if(x == 0) {
Root = merge(x,y);
return -2147483647; // 或根据题目要求处理
}
root=x;
while(tr[root].rc){
root=tr[root].rc;
}
ans=tr[root].val;
Root=merge(x,y);
return ans;
}
ll nxt(ll z){//查找后驱
ll x,y,root;
ll ans=0;
split(Root,z,x,y);
if(y == 0) {
Root = merge(x,y);
return -2147483647; // 或根据题目要求处理
}
root=y;
while(tr[root].lc){
root=tr[root].lc;
}
ans=tr[root].val;
Root=merge(x,y);
return ans;
}
int main(){
tr[0].siz = 0; // 空节点的大小为 0
srand(time(0));
ll n,opt,x;
cin>>n;
while(n--){
cin>>opt>>x;
if(opt==1){
insert(x);
}
if(opt==2){
remove(x);
}
if(opt==3){
cout<<get_rank(x)<<endl;
}
if(opt==4){
cout<<pm(x)<<endl;
}
if(opt==5){
cout<<prev(x)<<endl;
}
if(opt==6){
cout<<nxt(x)<<endl;
}
}
}
可以自由转载

浙公网安备 33010602011771号