1. 程式人生 > 實用技巧 >非旋轉treap之普通平衡樹

非旋轉treap之普通平衡樹

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef pair<int,int> pii;
int tot,son[100005][2],c[100005],val[100005],root;
int read()
{
    int x=0,f=1;
    char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
    return x*f;
}
int random(int lim)
{
    return rand()%lim+1;
}
void updata(int a)
{
    c[a]=c[son[a][0]]+1+c[son[a][1]];
}
int getrank(int v)  //查詢權值為v的數字的排名 
{
    int res=0;
    for(int x=root;x;)
    {
        if(val[x]<v)    
		//如果當前根結點小於v,則所有v及其左子樹均小於v 
        {
            res+=c[son[x][0]]+1;
            x=son[x][1];
        }
        else
             x=son[x][0];
    }
    return res+1;
}
pii split(int a,int k)
//從a這個樹中分出K個點來,
//這k個點所組成的樹的樹根做為其左返回值,其它的結點所形成的樹做為右返回值
{
    if(c[a]==k)  //如果a這個樹正好有k個結點,則直接返回a這個樹,右返回值為0
	return make_pair(a,0);
    if(k==0)
	return make_pair(0,a);//左邊為空樹,右為原來a這個樹 
    pii tmp;
    if(c[son[a][0]]>=k)//如果左子樹結點個數大於等於k 
    {
        tmp=split(son[a][0],k);//從左子樹中分離 
        son[a][0]=tmp.second;//a的左子樹只剩下了分離後的結點 
        updata(a);//更新a的相關值 
        return make_pair(tmp.first,a);//返回分離後的樹與從前a樹剩下的部分 
    }
    else
    {
        tmp=split(son[a][1],k-c[son[a][0]]-1);//減去左子樹及根結點
        son[a][1]=tmp.first;
        updata(a);
        return make_pair(a,tmp.second);
    }
}
int merge(int a,int b)
//將根結點編號分為a,b的樹進行合併
//此時b樹中所有點權值大於a樹中的所有點權 
{
    if(!a||!b)return a+b;
    if(random(c[a]+c[b])<=c[a])
    {
        son[a][1]=merge(son[a][1],b);//將b做為a的右子樹 
        updata(a);
        return a;
    }
    else
    {
        son[b][0]=merge(a,son[b][0]);//將a做為b的左子樹 
        updata(b);
        return b;
    }
}
void insert(int v)
{
    tot++;
    val[tot]=v;
    memset(son[tot],0,sizeof(son[tot]));
    c[tot]=1;
    int x=getrank(v)-1;
    pii tmp=split(root,x);
	//從root中分離出前x個結點,tmp.first為分裂後左樹的根結點編號 
	//tmp.second為分裂後右根的根結點編號 
    root=merge(merge(tmp.first,tot),tmp.second);
    //先將第tot個點與分離出來的左樹合併,再與其右樹合併 
    return;
}
void del(int v) //刪除權值為v的數字 
{
    int x=getrank(v);
    pii tmp=split(root,x);
    int c=tmp.second;
    tmp=split(tmp.first,x-1);
    root=merge(tmp.first,c);
}
int getval(int a,int k)//查詢第k小的數字 
{
    if(!k)return 0;
    if(c[son[a][0]]>=k)return getval(son[a][0],k);
    if(c[son[a][0]]+1==k)return a;
    return getval(son[a][1],k-c[son[a][0]]-1);
}
int main()
{
    srand(20020220);
    int n=read();
    for(int i=1;i<=n;i++)
    {
        int mode=read(),x=read();
        if(mode==1)insert(x);
        if(mode==2)del(x);
        if(mode==3)printf("%d\n",getrank(x));
        if(mode==4)printf("%d\n",val[getval(root,x)]);
        if(mode==5)printf("%d\n",val[getval(root,getrank(x)-1)]);
        if(mode==6)printf("%d\n",val[getval(root,getrank(x+1))]);
    }
    return 0;
}