bzoj3224 Tyvj 1728 普通平衡树题解--Treap

题面:

Description

您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
1. 插入x数
2. 删除x数(若有多个相同的数,因只删除一个)
3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
4. 查询排名为x的数
5. 求x的前驱(前驱定义为小于x,且最大的数)
6. 求x的后继(后继定义为大于x,且最小的数)

Input

第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6)

Output

对于操作3,4,5,6每行输出一个数,表示对应答案

Sample Input

10

1 106465

4 1

1 317721

1 460929

1 644985

1 84185

1 89851

6 81968

1 492737

5 493598

Sample Output

106465

84185

492737

HINT

1.n的数据范围:n<=100000

2.每个数的数据范围:[-2e9,2e9]
View Code

题解:

  今天第一次接触平衡二叉树的概念,做了一道模版题,觉得Treap这东西很神奇啊~

顾名思义,Treap=heap+tree,就是把堆和二叉树结合在了一起。

但是为什么不用一般的二叉树呢?(为了给我们增大代码量)不对,是因为普通树原来是log(n)级别的,但是经过各种insert啊,del啊什么的就可能失去“平衡”,节点集中在一侧什么的,结果成了一条长链,这就把log(n)的算法变成O(n)级的线性了。

而现在的Treap就是解决这个问题的方法之一。

Treap中的节点在满足树的性质(左儿子都小,右儿子都大之类的)的同时,还对每个节点加入了一个“优先级”,并将节点按照堆的性质排序。这里的优先级采用随机生成的方式,所以节点的左右分布是随机的,以此保证整棵树的相对平衡。

那我们怎么样对这些节点进行堆的排序呢?

这就有一个看起来很厉害的操作了--旋转

旋转分为左旋和右旋。当我们某个节点的左儿子优先度大于本节点,就需要进行右旋,右儿子大,就左旋。

二叉左旋
一棵二叉平衡树的子树,根是Root,左子树是x,右子树的根为RootR,右子树的两个孩子树分别为RLeftChild和RRightChild。则左旋后,该子树的根为RootR,右子树为RRightChild,左子树的根为Root,Root的两个孩子树分别为x(左)和RLeftChild(右)。
二叉右旋
一棵二叉平衡树的子树,根是Root,右子树是x,左子树的根为RootL,左子树的两个孩子树分别为LLeftChild和LRightChild。则右旋后,该子树的根为RootL,左子树为LLeftChild,右子树的根为Root,Root的两个孩子树分别为LRightChild(左)和x(右)。

来自百度百科,个人觉得挺容易懂的。

那么问题来了,为什么你这么一转,还能保持树的性质成立呢?为什么不会把节点权小的和大的弄返呢?不会把树弄乱吗?

这就是旋转的真正厉害之处了----可以发现,旋转前后,该子树的中序遍历是不变的!就是说并不会改变数列的大小顺序。我也不是很懂具体是为什么能这样,但是确实很厉害。

剩下就没什么了,树嘛,插入删除的都比较基础。

放代码:

 

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int maxn=100010,inf=100000000;
  4 int cnt,ret,n,t1,t2,root;
  5 struct treap{
  6     int lc,rc,key,pri,siz,val;
  7 /*key是关键字(权),pri是优先度,siz为子树大小,val表示key这个数有几个*/
  8 }a[maxn];
  9 void pushup(int &o){
 10     a[o].siz=a[a[o].lc].siz+a[a[o].rc].siz+a[o].val;
 11     return;
 12 }
 13 void lturn(int &o){
 14     int t=a[o].rc;
 15     a[o].rc=a[t].lc;
 16     a[t].lc=o;
 17     a[t].siz=a[o].siz;
 18     pushup(o);
 19     o=t;
 20     return;
 21 }
 22 void rturn(int &o){
 23     int t=a[o].lc;
 24     a[o].lc=a[t].rc;
 25     a[t].rc=o;
 26     a[t].siz=a[o].siz;
 27     pushup(o);
 28     o=t;
 29     return;
 30 }
 31 void insert(int &o,int t){
 32     if(!o){
 33         o=++cnt;
 34         a[o]=(treap){0,0,t,rand(),1,1};//rand()随机一个优先度
 35         return;
 36     }
 37     a[o].siz++;
 38     if(t==a[o].key)a[o].val++;
 39     else if(t<a[o].key){
 40         insert(a[o].lc,t);
 41         if(a[a[o].lc].pri>a[o].pri)rturn(o);
 42     }
 43     else{
 44         insert(a[o].rc,t);
 45         if(a[a[o].rc].pri>a[o].pri)lturn(o);//
 46     }
 47     return;
 48 }
 49 void del(int &o,int k){
 50     if(!o)return;
 51     if(k==a[o].key){
 52         if(a[o].val>1){
 53             a[o].val--;
 54             a[o].siz--;
 55         }
 56         else if(!(a[o].lc*a[o].rc)){//如果左右只有一个儿子
 57             o=a[o].lc+a[o].rc;
 58         }
 59         else if(a[a[o].lc].pri<a[a[o].rc].pri){
 60             lturn(o);
 61             del(o,k);
 62         }
 63         else{
 64             rturn(o);
 65             del(o,k);
 66         }
 67     }
 68     else if(k<a[o].key)
 69     {
 70         --a[o].siz;
 71         del(a[o].lc,k);
 72     }
 73     else
 74     {
 75         --a[o].siz;
 76         del(a[o].rc,k);
 77     }
 78     return;
 79 }
 80 int query_rank(int o,int k){
 81     if(!o)return 0;
 82     if(k<a[o].key)return query_rank(a[o].lc,k);
 83     if(k==a[o].key)return a[a[o].lc].siz+1;
 84     return a[a[o].lc].siz+a[o].val+query_rank(a[o].rc,k);
 85 }
 86 int query_num(int o,int k){
 87     if(!o)return 0;
 88     if(k<=a[a[o].lc].siz)return query_num(a[o].lc,k);
 89     if(k<=a[a[o].lc].siz+a[o].val)return a[o].key;
 90     return query_num(a[o].rc,k-a[a[o].lc].siz-a[o].val);
 91 }
 92 void query_pre(int o,int k){
 93     if(!o)return;
 94     if(k<=a[o].key)query_pre(a[o].lc,k);
 95     else{
 96         ret=a[o].key;
 97         query_pre(a[o].rc,k);
 98     }
 99     return;
100 }
101 void query_pos(int o,int k){
102     if(!o)return;
103     if(k>=a[o].key)query_pos(a[o].rc,k);
104     else{
105         ret=a[o].key;
106         query_pos(a[o].lc,k);
107     }
108     return;
109 }
110 int main(){
111     scanf("%d",&n);
112     srand(n);
113     for(int i=1;i<=n;i++){
114         scanf("%d%d",&t1,&t2);
115         if(t1==1)insert(root,t2);
116         else if(t1==2)del(root,t2);
117         else if(t1==3)printf("%d\n",query_rank(root,t2));
118         else if(t1==4)printf("%d\n",query_num(root,t2));
119         else if(t1==5){
120             ret=-inf;
121             query_pre(root,t2);
122             printf("%d\n",ret);
123         }
124         else if(t1==6){
125             ret=inf;
126             query_pos(root,t2);
127             printf("%d\n",ret);
128         }
129     }
130     return 0;
131 }

 

 

 

posted @ 2017-09-18 23:18  Requiescat  阅读(210)  评论(0编辑  收藏  举报