Treap

POJ - 3481
警告:千万不要初始化种子,这oj会RE被坑了一天QAQ。
Treap就是一个用随机数优化了的二叉搜索树,二叉搜索树满足某个节点的值大于等于左儿子节点的值,小于右儿子节点的值,但是这样插入的值就会有可能形成一条链造成很低的效率,所以采用了用随机数优化的方法,随机的给每一个节点赋予一个优先级,在插入节点时,节点的优先级满足堆的性质(小顶堆或大顶堆),值满足二叉搜索树的性质,这就是一颗Treap。

为了满足上述的两个性质,在每次插入的时候都要对节点进行旋转操作,因为每次插入的时候都是直接插到叶子节点的,所以每次递归回去的时候就要进行旋转操作,以让Treap满足堆的性质。旋转操作是不会改变Treap的中序遍历的结果的,也就是说不会破坏二叉搜索树的性质,而且可以让Treap满足堆的性质。

#include<cstdio>
#include<cstring>
#include<ctime>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=1e6+10;
struct Treap
{
    struct zp
    {
        int son[2];
        int fix,id,p;
    } tree[maxn];
    int root,sz;
    void init()
    {
        root=0;
        sz=0;
    }
    int newnode(int id,int p)
    {
        sz++;
        tree[sz].fix=rand();//随机优先级
        tree[sz].id=id,tree[sz].p=p;
        tree[sz].son[0]=tree[sz].son[1]=0;
        return sz;
    }
    void rotate(int &o,int d)//旋转操作 0代表左旋 1代表右旋
    {
        int k=tree[o].son[d^1];
        tree[o].son[d^1]=tree[k].son[d];
        tree[k].son[d]=o;
        o=k;
    }
    void remove(int &u,int p)//删除操作 删除题目上优先级为p的节点
    {
        if(tree[u].p==p)
        {
            if(tree[u].son[0]!=0&&tree[u].son[1]!=0)//当这个点的两个儿子都不为空时为了删除它就要将它往下旋转,直到它的某个儿子为空为止
            {
                int d=tree[tree[u].son[0]].fix<tree[tree[u].son[1]].fix?0:1;//判断是左旋还是右旋
                rotate(u,d);
                remove(tree[u].son[d],p);//递归删除
            }
            else//某个儿子节点为空后删除节点,将不为空的节点接到它的父节点上
            {
                    if(tree[u].son[0]==0) u=tree[u].son[1];
                    else u=tree[u].son[0];
            }
        }
        else remove(tree[u].son[p>tree[u].p],p);
    }
    void insert(int &i,int id,int p)//插入
    {
        if(i==0) i=newnode(id,p);
        else
        {
            int d=p<tree[i].p?0:1;//判断找那个儿子
            insert(tree[i].son[d],id,p);
            if(tree[i].fix<tree[tree[i].son[d]].fix) rotate(i,d^1);//递归回来后进行旋转
        }
    }
    void query(int &i,int d)//查询最大值 最小值
    {
        if(i==0)
        {
            printf("0\n");
            return ;
        }
        if(tree[i].son[d]==0)
        {
            printf("%d\n",tree[i].id);
            remove(root,tree[i].p);
        }
        else query(tree[i].son[d],d);
    }
}ac;
int main()
{
    ac.init();
    int opt;
    while(scanf("%d",&opt)!=EOF && opt)
    {
        if(opt==1)
        {
            int id,p;
            scanf("%d%d",&id,&p);
            ac.insert(ac.root,id,p);
        }
        else ac.query(ac.root,(opt-2)^1);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值