【BZOJ3224】【tyvj1728】普通平衡树

最近开始学习平衡树,在学长的强烈推荐下学习了AVL、红黑树、splay(以上我都还没学)treap。

首先讲一下个人对treap(树堆)的理解。

treap,顾名思义,就是tree+heap,首先因为treap是一棵平衡树,因此它满足二叉排序树的性质,接下来,为了防止BST退化成一条链,它使用了随机化的方式给每个点分布一个优先级,然后要求优先级满足堆的性质,但不必是一棵完全二叉树,这样的效率期望就是每次基础操作\( \log n \)的。

然后简单讲一下树堆的基础操作,代码参见例题与AC代码。

1.插入     平衡树最基础的操作之一就是插入一个新节点,首先我们按照BST的性质插入这个节点,接下来按照优先级进行旋转维护堆的性质,这样就可以了。

2.删除   平衡树最基础的操作之二就是删除一个原有节点,同样的我们按照BST的性质找到这个节点,然后按照BST的方法删除它,接下来维护堆的性质即可。

3.查找     平衡树最基础的操作之三就是查找,一般主要包含2种查找:1)给定一个权值,查找排名 2)给定一个排名,查找权值 这2种操作是大同小异的,都只需要按照BST的性质来进行即可。

 

 

下面是本题题解。

题目就是平衡树最基础的操作裸题,所以就直接参考上面所说的以及代码就好了。(1912KB 232ms on BZOJ)

#include <stdio.h>
#define getchar() (S==TT&&(TT=(S=BB)+fread(BB,1,1<<15,stdin),S==TT)?EOF:*S++)
char BB[1<<15],*TT=BB,*S=BB;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9') f=ch=='-'?-1:1,ch=getchar();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return x*f;
}
inline int rad(){
    static int x=23333;
    x^=x<<13,x^=x>>17,x^=x<<5;return x;
}
struct treap{
    treap *ls,*rs;
    int val,pri,cnt,sz;
    treap(int val):val(val){ls=rs=NULL,cnt=sz=1,pri=rad();}
    void combine(){sz=cnt;if (ls!=NULL) sz+=ls->sz;if (rs!=NULL) sz+=rs->sz;}
}*root;
inline void lrotate(treap* &x){treap *y=x->rs;x->rs=y->ls;y->ls=x;y->sz=x->sz;x->combine();x=y;}
inline void rrotate(treap* &x){treap *y=x->ls;x->ls=y->rs;y->rs=x;y->sz=x->sz;x->combine();x=y;}
inline void Insert(treap* &x,int val){
    if (x==NULL){x=new treap(val); return;}
    if (val==x->val) x->cnt++;
    else if (val>x->val){Insert(x->rs,val);if (x->rs->pri<x->pri) lrotate(x);}
    else {Insert(x->ls,val);if (x->ls->pri<x->pri) rrotate(x);}x->combine();
}
void Delete(treap *&x,int val){
    if (x==NULL) return;
    if (val==x->val){
        if (x->cnt>1) x->cnt--,x->sz--;
        else if (x->ls==NULL||x->rs==NULL){
            treap *t=x;
            if (x->ls==NULL) x=x->rs;
            else x=x->ls;
            delete t;
        }
        else if (x->ls->pri<x->rs->pri)
            rrotate(x),Delete(x,val);
        else lrotate(x),Delete(x,val);
    }
    else if (val<x->val) x->sz--,Delete(x->ls,val);
    else x->sz--,Delete(x->rs,val);
}
inline int find(treap *x,int val){
    if (x==NULL) return 0;
    if (x->ls==NULL){
        if (val==x->val) return 1;
        if (val>x->val) return find(x->rs,val)+x->cnt;
        return 0;
    }
    if (val==x->val)return x->ls->sz+1;
    if (val<x->val) return find(x->ls,val);
    return find(x->rs,val)+x->ls->sz+x->cnt;
}
inline int find_rank(treap *x,int k){
    if (x==NULL) return 0;
    if (x->ls==NULL){
        if (k<=x->cnt) return x->val;
        else return find_rank(x->rs,k-x->cnt);
    }
    if (k<=x->ls->sz) return find_rank(x->ls,k);
    if (k>x->ls->sz+x->cnt) return find_rank(x->rs,k-x->ls->sz-x->cnt);
    return x->val;
}
int find_pre(treap *x,int val,int ans){
    if (x==NULL) return ans;
    if (val>x->val) return find_pre(x->rs,val,x->val);
    return find_pre(x->ls,val,ans);
}
int find_nxt(treap *x,int val,int ans){
    if (x==NULL) return ans;
    if (val<x->val) return find_nxt(x->ls,val,x->val);
    return find_nxt(x->rs,val,ans);
}
int main(){
    int q=read(); 
    while (q--){
        int opt=read(),x=read();
        switch (opt){
            case 1:Insert(root,x); break;
            case 2:Delete(root,x); break;
            case 3:printf("%d\n",find(root,x)); break;
            case 4:printf("%d\n",find_rank(root,x)); break;
            case 5:printf("%d\n",find_pre(root,x,-1)); break;
            case 6:printf("%d\n",find_nxt(root,x,-1)); break; 
        }
    }
}

 

posted @ 2017-05-03 09:08  Melacau  阅读(415)  评论(0编辑  收藏  举报