码迷,mamicode.com
首页 > 其他好文 > 详细

朴素的treap

时间:2017-12-24 23:00:40      阅读:309      评论:0      收藏:0      [点我收藏+]

标签:using   函数   line   sig   cas   就是   [1]   平衡   lin   

所谓Treap,就是一种二叉查找树,而我们知道二叉查找树,相对来说比较容易形成最坏的链表情况,所以我们有一种数据结构来防止二叉查找树出现最坏情况,那就是Treap。

Treap=tree+heap,Treap就是这样一种既是树又是堆的奇怪的东东。我们每次插入节点时,便随机的给每个节点赋给一个值,我们要求原始数据满足二叉查找树的性质,而随机值要满足堆的性质。

比如下面的一棵树:

技术分享图片

   首先我们知道各个节点的“优先级”是采用随机数的方法,那么就存在一个问题,当我们插入一个节点后,优先级不满足“堆定义"的。那么我们就要旋转这课树。

①: 左左情况旋转

技术分享图片

②: 右右情况旋转

技术分享图片

好在我们写一个旋转函数就可以同时维护左旋和右旋了:

void play(Treap* &rr,int d){
    Treap *k=rr->ro[d^1];
    rr->ro[d^1]=k->ro[d];//ro[0]是左孩子,ro[1]是右孩子
    k->ro[d]=rr;
    rr->rub();//rub()函数的作用是重新统计该子树的大小
    k->rub();//必须先rr再k,因为现在rr是k的孩子
    rr=k;
}

那么我们就可以刷水题了:(洛谷-普通平衡树)

#include<bits/stdc++.h>
#define sight(c) (‘0‘<=c&&c<=‘9‘)
#define RR NULL
#define inf 1<<29
#define random rrsbRRsb
using namespace std;
inline int random(){
    static int seed=707; 
    return seed=int(seed*48271LL%2147483647);
}
struct Treap{
    int key,rap,siz;
    Treap *ro[2];
    Treap(int k){
        siz=1;
        key=k;
        rap=random();
        ro[1]=ro[0]=RR;
    }
    inline void rub() {
        siz=1;
        if (ro[0]!=RR) siz+=ro[0]->siz;
        if (ro[1]!=RR) siz+=ro[1]->siz;
    }
    inline int cop(int x){
        if (x==key) return -1;
        return x<key?0:1;
    }
};
inline void read(int &x) {
    static char c; static int b;
    for (b=1,c=getchar();!sight(c);c=getchar()) if (c==-) b=-1;
    for (x=0;sight(c);c=getchar()) x=x*10+c-48;
    x*=b;
}
void play(Treap* &rr,int d){
    Treap *k=rr->ro[d^1];
    rr->ro[d^1]=k->ro[d];
    k->ro[d]=rr;
    rr->rub();
    k->rub();
    rr=k;
}
void Insert(Treap* &rr,int x){
    if (rr==RR) rr=new Treap(x);
    else {
        int d=x < rr->key?0:1;
        Insert(rr->ro[d],x);
        if (rr->ro[d]->rap > rr->rap)
         play(rr,d^1);
    }
    rr->rub();
}
bool Find(Treap *p,int x){
    while(p!=RR) {
        int d=p->cop(x);
        if (d==-1) return true;
        p=p->ro[d];
    }
    return false;
}
void Delete(Treap* &t,int x){
    int d=t->cop(x);
    if (d==-1) {
        Treap *tmp=t;
        if (t->ro[0]==RR) {
            t=t->ro[1];
            delete tmp;
            tmp=RR;
        } else if (t->ro[1]==RR) {
            t=t->ro[0];
            delete tmp;
            tmp=RR;
        } else {
            int k=t->ro[0]->rap<t->ro[1]->rap?0:1;
            play(t,k);
            Delete(t->ro[k],x);
        }
    }
    else Delete(t->ro[d],x);
    if (t!=RR) t->rub();
}
int Kth(Treap *t,int k){
    int cm=0;
    if (t->ro[0]) cm=t->ro[0]->siz;  
    cm++;
    if (cm==k)
     return t->key;
    if (cm>k) return Kth(t->ro[0],k);
    return Kth(t->ro[1],k-cm);
}
int Rank(Treap *t,int k){
    int r;
    if (!t) return inf;
    if (t->ro[0]==RR) 
     r=0;else r=t->ro[0]->siz;
    if(k==t->key) return min(r+1,Rank(t->ro[0],k));
    if(k<t->key) 
     return Rank(t->ro[0],k);
    return r+1+Rank(t->ro[1],k);
}
int Pre(Treap *t,int k){
    if (!t) return -inf;
    if (k>t->key) return max(t->key,Pre(t->ro[1],k));
    return Pre(t->ro[0],k);
}
int Sub(Treap *t,int k){
    if (!t) return inf;
    if (k<t->key) return min(t->key,Sub(t->ro[0],k));
    return Sub(t->ro[1],k);
}
int n,op,x;
int main () {
    freopen("a.in","r",stdin);
    read(n);
    Treap* root=RR;
    while (n--) {
        read(op); read(x);
        switch(op){
            case 1:Insert(root,x);break;
            case 2:Delete(root,x);break;
            case 3:printf("%d\n",Rank(root,x));break;
            case 4:printf("%d\n",Kth(root,x));break;
            case 5:printf("%d\n",Pre(root,x));break;
            case 6:printf("%d\n",Sub(root,x));break;
        }
    //    cout<<op<<endl;
    }
    return 0;
}

朴素的treap

标签:using   函数   line   sig   cas   就是   [1]   平衡   lin   

原文地址:http://www.cnblogs.com/rrsb/p/8099273.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!