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;
}
882

被折叠的 条评论
为什么被折叠?



