Treap,由Tree和Heap各取一半组成的单词,也可意为树堆。
二叉查找树为每一个结点设置了一个键值,Treap树在上面又加了一个被称为优先级的权值。对键值来说,Treap树是排序二叉树;对优先级来说,Treap树是堆——在这棵树的任意子树上,根节点的优先级最大。
Treap的唯一性指:另每个节点的优先级互不相等,则该棵树的形态唯一,与元素的插入顺序无关。
上图描述了Treap树的建树过程。
节点定义:
1 struct Node 2 { 3 int size; 4 int rank; 5 int key; 6 Node *son[2]; 7 bool operator < (const Node &a)const 8 { 9 return rank<a.rank; 10 } 11 int cmp(int x)const 12 { 13 if(x==key) return -1; 14 return x<key?0:1; 15 } 16 void update() 17 { 18 size=1+son[0]->size+son[1]->size; 19 } 20 };
首先我们来实现插入操作。
方法一:已知优先级,按照优先级由大到小排序,然后键值比根节点小的放左子树,大的放右子树。
方法二:按照BST的插入先将新结点插入到所在位置,然后为该节点分配一个随机的优先级,比较和根节点优先级的大小,如果比根节点大,那么就往上走。
1 void rotate(Node* &o,int d) 2 { 3 Node *k=o->son[d^1]; 4 o->son[d^1]=k->son[d]; 5 k->son[d]=o; 6 o->update(); 7 k->update(); 8 o=k; 9 } 10 void build(Node* &o,int x) 11 { 12 if(o==null) 13 { 14 o=new Node(); 15 o->son[0]=o->son[1]=null; 16 o->rank=rand(); 17 o->key=x; 18 o->size=1; 19 } 20 else 21 { 22 int d=o->cmp(x); 23 build(o->son[d],x); 24 o->update(); 25 if(o<o->son[d]) 26 rotate(o,d^1); 27 } 28 }
因为我们需要修改o的值,所以在形参里用了*&
然后是找到x的在Treap树里的排名。所以我们只需要判断比它大的元素有几个就好了。
int kth(Node* o,int k) { if(o==null||k<=0||k>o->size) return -1; int s=o->son[1]==null?0:o->son[1]->size; if(k==s+1) return o->key; else if(k<=s) return kth(o->son[1],k); else return kth(o->son[0],k-s-1); }
接着是找到排名第x的元素。
1 int find(Node* o,int k) 2 { 3 if(o==null) return -1; 4 int d=o->cmp(k); 5 if(d==-1) return o->son[1]->size+1; 6 else if(d==1) return find(o->son[d],k); 7 else 8 { 9 int tmp=find(o->son[d],k); 10 if(tmp==-1) return -1; 11 else return tmp+1+o->son[1]->size; 12 } 13 }
然后是删除元素x
1 void erase(Node *&t, int x) { 2 if (t == null)return; 3 if (t->key == x) { 4 if (t->son[0] == null || t->son[1] == null) { 5 Node *p = t; 6 if (t->son[0] == null) 7 t = t->son[1]; 8 else 9 t = t->son[0]; 10 delete p; 11 } 12 else { 13 int d = t->son[0] > t->son[1] ? 1 : 0; 14 rotate(t, d ^ 1); 15 erase(t->son[d], x); 16 } 17 } 18 else if (x < t->key)erase(t->son[0], x); 19 else erase(t->son[1], x); 20 }
以下为例题。
HUD4585 Shaolin
Problem Description
Shaolin temple is very famous for its Kongfu monks.A lot of young men go to Shaolin temple every year, trying to be a monk there. The master of Shaolin evaluates a young man mainly by his talent on understanding the Buddism scripture, but fighting skill is also taken into account.
When a young man passes all the tests and is declared a new monk of Shaolin, there will be a fight , as a part of the welcome party. Every monk has an unique id and a unique fighting grade, which are all integers. The new monk must fight with a old monk whose fighting grade is closest to his fighting grade. If there are two old monks satisfying that condition, the new monk will take the one whose fighting grade is less than his.
The master is the first monk in Shaolin, his id is 1,and his fighting grade is 1,000,000,000.He just lost the fighting records. But he still remembers who joined Shaolin earlier, who joined later. Please recover the fighting records for him.
When a young man passes all the tests and is declared a new monk of Shaolin, there will be a fight , as a part of the welcome party. Every monk has an unique id and a unique fighting grade, which are all integers. The new monk must fight with a old monk whose fighting grade is closest to his fighting grade. If there are two old monks satisfying that condition, the new monk will take the one whose fighting grade is less than his.
The master is the first monk in Shaolin, his id is 1,and his fighting grade is 1,000,000,000.He just lost the fighting records. But he still remembers who joined Shaolin earlier, who joined later. Please recover the fighting records for him.
Input
There are several test cases.
In each test case:
The first line is a integer n (0 <n <=100,000),meaning the number of monks who joined Shaolin after the master did.(The master is not included).Then n lines follow. Each line has two integer k and g, meaning a monk's id and his fighting grade.( 0<= k ,g<=5,000,000)
The monks are listed by ascending order of jointing time.In other words, monks who joined Shaolin earlier come first.
The input ends with n = 0
In each test case:
The first line is a integer n (0 <n <=100,000),meaning the number of monks who joined Shaolin after the master did.(The master is not included).Then n lines follow. Each line has two integer k and g, meaning a monk's id and his fighting grade.( 0<= k ,g<=5,000,000)
The monks are listed by ascending order of jointing time.In other words, monks who joined Shaolin earlier come first.
The input ends with n = 0
Output
A fight can be described as two ids of the monks who make that fight. For each test case, output all fights by the ascending order of happening time. Each fight in a line. For each fight, print the new monk's id first ,then the old monk's id.
Sample Input
3
2 1
3 3
4 2
0
Sample Output
2 1
3 2
4 2
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <time.h> 5 #include <stdlib.h> 6 #include <math.h> 7 using namespace std; 8 int vis[5000000+5]; 9 struct Node 10 { 11 int size; 12 int rank; 13 int key; 14 Node *son[2]; 15 bool operator < (const Node &a)const 16 { 17 return rank<a.rank; 18 } 19 int cmp(int x)const 20 { 21 if(x==key) return -1; 22 return x<key?0:1; 23 } 24 void update() 25 { 26 size=1+son[0]->size+son[1]->size; 27 } 28 }; 29 struct Treap 30 { 31 Node *root; 32 Node *null=new Node(); 33 void init() 34 { 35 srand(time(NULL)); 36 root=null; 37 } 38 void rotate(Node* &o,int d) 39 { 40 Node *k=o->son[d^1]; 41 o->son[d^1]=k->son[d]; 42 k->son[d]=o; 43 o->update(); 44 k->update(); 45 o=k; 46 } 47 void build(Node* &o,int x) 48 { 49 if(o==null) 50 { 51 o=new Node(); 52 o->son[0]=o->son[1]=null; 53 o->rank=rand(); 54 o->key=x; 55 o->size=1; 56 } 57 else 58 { 59 int d=o->cmp(x); 60 build(o->son[d],x); 61 o->update(); 62 if(o<o->son[d]) 63 rotate(o,d^1); 64 } 65 } 66 int kth(Node* o,int k) 67 { 68 if(o==null||k<=0||k>o->size) return -1; 69 int s=o->son[1]==null?0:o->son[1]->size; 70 if(k==s+1) return o->key; 71 else if(k<=s) return kth(o->son[1],k); 72 else return kth(o->son[0],k-s-1); 73 } 74 int find(Node* o,int k) 75 { 76 if(o==null) return -1; 77 int d=o->cmp(k); 78 if(d==-1) return o->son[1]->size+1; 79 else if(d==1) return find(o->son[d],k); 80 else 81 { 82 int tmp=find(o->son[d],k); 83 if(tmp==-1) return -1; 84 else return tmp+1+o->son[1]->size; 85 } 86 } 87 } treap; 88 int main() 89 { 90 int n; 91 while(~scanf("%d",&n)&&n) 92 { 93 treap.init(); 94 int x,y; 95 scanf("%d%d",&x,&y); 96 treap.build(treap.root,y); 97 vis[y]=x; 98 printf("%d %d ",x,1); 99 for(int i=2;i<=n;i++) 100 { 101 scanf("%d%d",&x,&y); 102 vis[y]=x; 103 treap.build(treap.root,y); 104 int t=treap.find(treap.root,y); 105 int ans1,ans2,ans; 106 ans1=treap.kth(treap.root,t-1); 107 ans2=treap.kth(treap.root,t+1); 108 if(ans1!=-1&&ans2!=-1) 109 { 110 ans=ans1-y>=y-ans2?ans2:ans1; 111 } 112 else if(ans1==-1) ans=ans2; 113 else ans=ans1; 114 printf("%d %d ",x,vis[ans]); 115 } 116 } 117 return 0; 118 }
之后会把hdu3726也加上来。