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