平衡树-有旋Treap

有旋Treap

可以在普通二叉搜索树的基础上保持优秀log复杂度

代码里有较为详细的注释

所以,话不多说,放代码qwq

#include<iostream>
using namespace std;
#define lid d[id].l
#define rid d[id].r
int cnt_tree,ans;

struct Treap{
    int l,r; //左孩子,右孩子
    int siz; //大小
    int cnt; //重复元素数量
    int rank; //随机出来的优先度
    int val; //值
}d[100005];

void Update_size(int id){//更新大小
    d[id].siz=d[id].cnt+d[lid].siz+d[rid].siz;
}

void lrotate(int &id){
  /* 左旋:也就是让右子节点变成根节点
   *         A                 C
   *        / \               / \
   *       B  C    ---->     A   E
   *         / \            / \
   *        D   E          B   D
   */
    int t=d[id].r; //记录右孩子
    d[id].r=d[t].l; //A的右孩子改为C的左孩子
    d[t].l=id; //C的左孩子改为A
    d[t].siz=d[id].siz;//传递size
    Update_size(id);//更新A的size
    id=t;//换根
}

void rrotate(int &id){
   /* 右旋:也就是让左子节点变成根节点
    *         A                 C
    *        / \               / \
    *       B  C    <----     A   E
    *         / \            / \
    *        D   E          B   D
    */
    int t=d[id].l;//同上
    d[id].l=d[t].r;
    d[t].r=id;
    d[t].siz=d[id].siz;
    Update_size(id);
    id=t;
}

void insert(int &id,int val){
    if(!id){ //没有点新建点
        id=++cnt_tree;
        d[id].rank=rand();
        d[id].siz=1;
        d[id].cnt=1;
        d[id].val=val;
        return;
    }
    d[id].siz++; //大小++
    if(val==d[id].val){
        d[id].cnt++; //值相同,直接扔进去
    }
    else if(val<d[id].val){
        insert(lid,val); //增加在左孩子里
        if(d[lid].rank<d[id].rank){
            rrotate(id); //为满足小根堆性质(上方优先度低于下方),需要右旋
        }
    }
    else{
        insert(rid,val); //同上
        if(d[rid].rank<d[id].rank){
            lrotate(id);
        }
    }
}
//用bool,0为未删点,1为删点
bool del(int &id,int val){
    if(!val) return false; //如果没有点,不需要修改,所以return false
    if(val==d[id].val){ //如果相等
        if(d[id].cnt>1){ //有重复元素则直接删除
            d[id].cnt--;
            d[id].siz--;
            return true;
        }
        if(lid==0 || rid==0){ //只有一个孩子,或没有孩子,不存在内讧,故直接赋值
            id=lid+rid;
            return true;
        }
        else if(d[lid].rank<d[rid].rank){ //删完还要满足小根堆,故右旋
            rrotate(id);
            return del(id,val); //删点
        }
        else{
            lrotate(id);
            return del(id,val);
        }
    }
    else if(val<d[id].val){
        bool dele=del(lid,val); //点在左孩子,记录是否成功删点
        if(dele) d[id].siz--;
        return dele;
    }
    else{
        bool dele=del(rid,val);
        if(dele) d[id].siz--;
        return dele;
    }
}

int Query_Rank(int id,int val){ //查询排名
    if(!id) return 0; //若 定义排名为比当前数小的数的个数+1 则此处应该为return 1;
    if(val==d[id].val) return d[lid].siz+1; //仅比所有左侧节点大
    else if(val<d[id].val) return Query_Rank(lid,val); //点在左孩子
    else return d[lid].siz+d[id].cnt+Query_Rank(rid,val); //1.比所有左节点大,2.比该节点的所有重复元素大,3.点在右孩子
}

int Query_Num(int id,int val){ //查询排名为val的节点值
    if(!id) return 0;
    if(val<=d[lid].siz) return Query_Num(lid,val); //节点在左孩子
    else if(val>d[lid].siz+d[id].cnt) return Query_Num(rid,val-d[lid].siz-d[id].cnt); //!节点在右孩子,但排名在右孩子里应减小
    else return d[id].val; //不在左,不在右,就只能在自己里了呗awa
}

void Query_Pre(int id,int val){ //查询前驱
    if(!id) return; //类似二分查找
    if(val>d[id].val){ //!别弄反了 
        ans=id;
        Query_Pre(rid,val);
    }
    else{
        Query_Pre(lid,val);
    }
}

void Query_Sub(int id,int val){
    if(!id) return;
    if(val<d[id].val){ //!别弄反了
        ans=id;
        Query_Sub(lid,val);
    }
    else{
        Query_Sub(rid,val);
    }
}

int main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int n,root=0;
    cin>>n;
    for(int i=1;i<=n;i++){
        int op,x;
        cin>>op>>x;
        if(op==1){
            insert(root,x);
        }
        if(op==2){
            del(root,x);
        }
        if(op==3){
            cout<<Query_Rank(root,x)<<"\n";
        }
        if(op==4){
            cout<<Query_Num(root,x)<<"\n";
        }
        if(op==5){
            ans=0;
            Query_Pre(root,x);
            cout<<d[ans].val<<"\n";
        }
        if(op==6){
            ans=0;
            Query_Sub(root,x);
            cout<<d[ans].val<<"\n";
        }
    }
}
posted @ 2024-08-23 18:07  QEDQEDQED  阅读(24)  评论(1编辑  收藏  举报