关于对treap的个人理解

目的

普通的二叉搜索树容易退化成一条链,使查询的复杂度从Ologn)变为O(n),所以使用随机数 数组辅助使其不易退化

性质

1val数组满足二叉搜索树的性质,即左子树内所有节点的val值小于根节点的val,右子树内的所有节点的val值大于根节点的val值(val数组内存的是题目中给出的要放进去的值);

2key数组满足小(大)根堆的性质,即所有子树的key值小(大)于根节点的key值;

作用

查找前驱,后继;动态加点,删点;动态维护一个有序数集;

操作:

基本操作有

右旋:(因为key值不满足小(大)根堆的特性)将这个节点的左儿子旋到这个节点的位置,

设此节点为p,其左儿子为ls

因为val[ls]<val[p](性质一)

所以在将ls旋到p的位置这个过程中为了维护性质一,让p成为ls的右儿子,而ls原本的右儿子,设其为 x,因为val[x]<val[p](性质一)key[x]<key[p](性质二),而此时p的左儿子的为空(因为p的左儿子成了p的父亲节点)所以将x变成p的左儿子;

左旋 :(因为key值不满足小(大)根堆的特性)将这个节点的右儿子旋到这个节点的位置(操作原理同上)

模板 (前驱,后继,第k大值,某数的排名)

 https://loj.ac/problem/104

#include<bits/stdc++.h>
using namespace std;
#define ll long long
void FRE(){freopen(".in","r",stdin);freopen(".out","w",stdout);}
void FCL(){fclose(stdin);fclose(stdout);}
inline ll rd()
{
    ll x=0,ert=1;char lk=getchar();
    while(!isdigit(lk)){if(lk=='-') ert=-1;lk=getchar();}
    while(isdigit(lk)){x=(x<<3)+(x<<1)+(lk-'0');lk=getchar();}
    return x*ert;
}
const int N=1e5+10,inf=1e9;
int ls[N],rs[N],val[N],sz[N],cn[N],cnt,ra[N],rt;
void up(int p){sz[p]=sz[ls[p]]+sz[rs[p]]+cn[p];}
void ltu(int &p){int t=ls[p];ls[p]=rs[t];rs[t]=p;p=t;up(rs[p]);up(p);}
void rtu(int &p){int t=rs[p];rs[p]=ls[t];ls[t]=p;p=t;up(ls[p]);up(p);}
void ins(int &p,int x)
{
    if(!p){p=++cnt;val[p]=x;sz[p]=1;cn[p]=1;ra[p]=rand();return ;}
    if(val[p]==x){cn[p]++;sz[p]++;return ;}
    if(x<val[p]) {ins(ls[p],x);if(ra[ls[p]]<ra[p]) ltu(p);up(p);}
    else {ins(rs[p],x);if(ra[rs[p]]<ra[p]) rtu(p);up(p);}
    return ;
}
void del(int &p,int x)
{
    if(p==0) return ;
    if(val[p]==x)
    {
        if(cn[p]>1){cn[p]--;sz[p]--;return ;}
        else if(!ls[p]||!rs[p]) {p=ls[p]+rs[p];return ;}
        else if(ra[ls[p]]<ra[rs[p]]) ltu(p),del(p,x);
        else rtu(p),del(p,x);return ;
    }
    sz[p]--;
    x<val[p]?del(ls[p],x):del(rs[p],x);
}
int rak(int p,int x)
{
    if(!p) return 0;
    if(val[p]==x) return sz[ls[p]]+1;
    return x<val[p]?rak(ls[p],x):rak(rs[p],x)+sz[ls[p]]+cn[p];
}
int num(int p,int x)
{
    if(!p) return inf;
    if(x<=sz[ls[p]]) return num(ls[p],x);
    if((x-sz[ls[p]])<=cn[p]) return val[p];
    return num(rs[p],x-sz[ls[p]]-cn[p]); 
}
int pre(int p,int x)
{
    if(!p) return -inf;
    return val[p]<x?max(val[p],pre(rs[p],x)):pre(ls[p],x);
}
int nxt(int p,int x)
{
    if(!p) return inf;
    return val[p]>x?min(val[p],nxt(ls[p],x)):nxt(rs[p],x);
}
int main()
{
    int n=rd();
    for(int i=1;i<=n;i++)
    {
        int opt=rd(),x=rd();
        switch(opt)
        {
            case 1:ins(rt,x);break;
            case 2:del(rt,x);break;
            case 3:printf("%d\n",rak(rt,x));break;
            case 4:printf("%d\n",num(rt,x));break;
            case 5:printf("%d\n",pre(rt,x));break;
            case 6:printf("%d\n",nxt(rt,x));break;
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/LWL--Figthing/p/9756238.html