平衡树总结

结合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;
        }
    }
}
posted @ 2025-08-28 14:34  MistyPost  阅读(7)  评论(0)    收藏  举报