题面:

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 Input101 1064654 11 3177211 4609291 6449851 841851 898516 819681 4927375 493598Sample Output10646584185492737HINT1.n的数据范围:n<=1000002.每个数的数据范围:[-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 }

转载于:https://www.cnblogs.com/Requiescat/p/7545898.html

bzoj3224 Tyvj 1728 普通平衡树题解--Treap相关推荐

  1. BZOJ 3224: Tyvj 1728 普通平衡树【Treap】

    3224: Tyvj 1728 普通平衡树 Time Limit: 10 Sec Memory Limit: 128 MB Description 您需要写一种数据结构(可参考题目标题),来维护一些数 ...

  2. bzoj3224: Tyvj 1728 普通平衡树(splay)

    3224: Tyvj 1728 普通平衡树 题目:传送门 题解: 啦啦啦啦又来敲个模版水经验啦~ 代码: 1 #include<cstdio> 2 #include<cstring& ...

  3. bzoj3224: Tyvj 1728 普通平衡树(打个splay暖暖手)

    (其实今天好热啊? 题目大意:插入,删除,k小,前驱后继,数的排名. splay和treap裸题...过几天补个treap的 splay: #include<iostream> #incl ...

  4. 替罪羊树—BZOJ3224: Tyvj 1728 普通平衡树

    冬令营被平衡树坑了之后,打算苦练一番数据结构(QAQ). 先是打了一下想学好久的替罪羊树. 替罪羊树实现方法很简单,就是在不满足平衡条件的时候暴力重构子树. 调试小结: 1.删除操作分两类情况:如果某 ...

  5. BZOJ 3224: Tyvj 1728 普通平衡树 treap

    3224: Tyvj 1728 普通平衡树 Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/p ...

  6. Treap树堆(bzoj 3224: Tyvj 1728 普通平衡树)

    Treap树堆:一种排序二叉树(中序遍历权值有序) 每个节点有两个关键字:key[]和rand[] 其中key[]满足二叉搜索树性质,rand[]满足堆性质(即Tree+Heap=Treap)即 如果 ...

  7. BZOJ 3224: Tyvj 1728 普通平衡树

    3224: Tyvj 1728 普通平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 9629  Solved: 4091 [Submit][S ...

  8. 3224: Tyvj 1728 普通平衡树

    3224: Tyvj 1728 普通平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 14480  Solved: 6275 Descripti ...

  9. 【Treap】[BZOJ 3224]Tyvj 1728 普通平衡树

    平衡树的入门题目,也可以用Treap来实现,我觉得Treap的核心就是那个rand()了用来保证树不退化成链,同时还是有平衡树的特性..总体来说我觉得比较好些,而且比较快 #include <c ...

最新文章

  1. war包解压不了_牛骨高汤的熬制方法,拿走不谢!有了这配方,还愁开不了小吃店?...
  2. vue 百度统计_百度暑期实习前端开发面经
  3. python程序设计——函数设计与调用
  4. flask数据库迁移理解及命令
  5. datatables.js 简单使用--多选框和服务器端分页
  6. 新风口?人造肉第一股表现强劲 股价累计上涨近600%
  7. [导入]ATA 50 pin to 40 pin
  8. linux usb bulk传输,2.1.1.2. USB MSC Bulk-Only (BBB) Transport
  9. java当前时间长整数值_在Java中获取当前年份的整数值
  10. linux下ftp服务站点,Linux下vsftp服务建立多站点的方法
  11. NPN和PNP三极管原理以及应用电路设计
  12. 信鸽推送避免打开多个相同的activity
  13. citespace:分析wos数据时显示“the timing slicing setting is outside the range of your data”解决方案
  14. 第一次在csdn写博客!
  15. 2022-04-19 Unity入门4——重要组件与API
  16. 关于移动端的touch事件(touchstart, touchmove, touchend,touchcancel)
  17. 开发工具---Eclipse 教程Ⅰ
  18. HTML游戏实战之《跳楼梯》
  19. 深度卷积神经网络中的patch
  20. 会计学原理知识点总结

热门文章

  1. python中的装饰器-(重复阅读)
  2. HDU 4747 Mex
  3. Java高级篇(二)——网络通信
  4. 阿里数据库内核月报:2017年04月
  5. 《图解CSS3:核心技术与案例实战》——1.3节渐进增强
  6. TODO:从数据库中随机抽取一条记录
  7. 原型模式——创建型模式
  8. 微信上传图文消息素材40007,invalid media_id hint
  9. 对测试人员或开发人员来说相互沟通有多重要?
  10. Wordpress 提速之 Gzip 压缩