平衡树模版WA了1,2两个点,玄关求调
查看原帖
平衡树模版WA了1,2两个点,玄关求调
1389794
Lei_ZT楼主2025/7/29 16:16
/*
note
定义:Treap(平衡树)实际上是大根堆和BST(二分搜索树)的结合体,在树种维护2个关键字key(适用于大根堆)和val(适用于BST) 
功能:维护一个动态的有序集合,支持快速地查找,插入,删除等操作,普通BST在特殊情况下
会退化为一条链,使得时间复杂度大大提升,Treap则是利用随机优先级旋转保持平衡,期望的
操作复杂度为O(logN) 


PS:只有删除和插入需要进行左旋右旋操作 
*/
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int MAXN=1000100;
LL root, tot, n;
const LL INF=0x7fffffffffffffffLL; 
int opt;
LL x; 
struct tree{
    LL p,lp,rp,size,val,key,cnt;
}t[MAXN];
void push_up(LL p){
    t[p].size=t[t[p].lp].size+t[t[p].rp].size+t[p].cnt;
}//易错点:忘记加上当前节点的cnt 
LL New(LL val){
    t[++tot].val=val;//为该节点赋值 
    t[tot].key=rand();//给该节点一个随机的优先级 
    t[tot].cnt=1;//该节点的数目 
    t[tot].size=1;//该以节点为根的子树的大小 
    t[tot].lp=t[tot].rp=0;//初始时该节点没有左右儿子 
    return tot;
}//新建一个节点 
void build(){
    root=New(-INF);
    t[root].rp=New(INF); 
    push_up(root);
}//建树操作,在一开始进行 
void zig(LL &p){
    LL q=t[p].lp;
    t[p].lp=t[q].rp;
    t[q].rp=p;
    p=q;  
    push_up(t[p].rp); 
    push_up(p);        
}
void zag(LL &p){
    LL q=t[p].rp;
    t[p].rp=t[q].lp;
    t[q].lp=p;
    p=q; 
    push_up(t[p].lp);  
    push_up(p);        
}

void insert(LL &p, LL val){
    if(p==0){//如果当前节点并不存在,直接新开一个节点 
        p=New(val);
        return;
    }
    if(val==t[p].val){ //找到了目标节点 
        t[p].cnt++;
        push_up(p);
        return;
    }
    if(val<t[p].val){//当前值大于目标值,搜索当前节点的左子树  
        insert(t[p].lp, val);
        if(t[p].key<t[t[p].lp].key)//检查当前相关的节点是否满足堆的性质 
            zig(p);//不满足,右旋 
    } 
	else{ 
        insert(t[p].rp, val);//当前值小于目标值,搜索右子树 
        if(t[p].key<t[t[p].rp].key)  
            zag(p);//不满足,左旋 
    }
    push_up(p); 
}

void delet(LL &p, LL val){
    if(p==0) return; //目标节点不存在 
    if(t[p].val==val){//找到了目标节点 
        if(t[p].cnt>1){ //直接减一 
            t[p].cnt--;
            push_up(p);
            return;
        }
        if(t[p].lp||t[p].rp){//存在子树 
            if(t[p].rp==0||t[t[p].lp].key>t[t[p].rp].key){
                zig(p);
                delet(t[p].rp,val);
            } 
			else{ 
                zag(p);
                delet(t[p].lp,val);
            }
            push_up(p);
        } 
		else{ 
            p=0;
        }
        return;
    }
    if(val<t[p].val) 
		delet(t[p].lp,val);
    else 
		delet(t[p].rp,val);
    push_up(p);
}
LL GetRank(LL p, LL val){
    if(p==0) 
		return 0;//目标节点不存在 
    if(val==t[p].val) 
		return t[t[p].lp].size+1;//找到目标节点 
    if(val<t[p].val)//目标值小于当前节点值,向左子树进行查找 
		return GetRank(t[p].lp,val);
    return GetRank(t[p].rp,val)+t[t[p].lp].size+t[p].cnt;//目标值大于当前值,向右子树查找 
}
LL GetVal(LL p, LL rank){
    if(p==0) return INF;//目标节点不存在 
    if(t[t[p].lp].size>=rank)//当前节点的排名大于目标排名,向左子树查找 
		return GetVal(t[p].lp,rank);
    if(t[t[p].lp].size+t[p].cnt>=rank)//所求排名只能为当前的节点 
		return t[p].val;
    return GetVal(t[p].rp,rank-t[t[p].lp].size-t[p].cnt);//当前节点的排名小于目标排名,向右子树查找 
}
LL GetPre(LL val){
    LL ans=1; //t[1].val==-INF
    LL p=root;
    while(p){
        if(val==t[p].val){//找到目标节点,则在其左子树中往右寻找  
            if(t[p].lp>0){
                p=t[p].lp;
                while(t[p].rp>0) p=t[p].rp;
                ans=p;
            }
            break;//跳出循环 
        }
        if(t[p].val<val&&t[p].val>t[ans].val) ans=p;
        p=(val<t[p].val)?t[p].lp:t[p].rp;
    }
    return t[ans].val;
}
LL GetNext(LL val){
    LL ans=2; //t[2].val=INF
    LL p=root;
    while(p){
        if(val==t[p].val){ 
            if(t[p].rp>0){
                p = t[p].rp;
                while(t[p].lp>0) p=t[p].lp;
                ans=p;
            }
            break;
        }
        if(t[p].val>val&&t[p].val<t[ans].val) ans=p;
        p=(val<t[p].val)?t[p].lp:t[p].rp;
    }
    return t[ans].val;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> n;
    build(); 
    while(n--){  
        cin>>opt>>x;
        if(opt==1) insert(root,x);        
        else if(opt==2) delet(root,x);    
        else if(opt==3) cout<<GetRank(root,x)-1<<endl;
        else if(opt==4) cout<<GetVal(root,x+1)<<endl;   
        else if(opt==5) cout<<GetPre(x)<<endl;     
        else if(opt==6) cout<<GetNext(x)<<endl; 
    }
    return 0;
}

2025/7/29 16:16
加载中...