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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/287848.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Blazor University (18)使用 RenderFragments 模板化组件 —— 创建 TabControl

原文链接&#xff1a;https://blazor-university.com/templating-components-with-renderfragements/creating-a-tabcontrol/创建一个 TabControl 组件源代码[1]接下来我们将创建一个 TabControl 组件。这将教您如何实现以下目标&#xff1a;将数据传递到 RenderFragment 以为其…

Java之GC机制

1 JVM基本结构 1&#xff09;类加载器classLoader&#xff1a;在JVM启动时或者类运行时将需要的.class文件加载到内存中 2&#xff09;内存区域&#xff08;运行时数据区&#xff09;&#xff1a; 是在JVM运行的时候操作所分配的内存区 3&#xff09;执行引擎&#xff1a;负…

《零基础看得懂的C语言入门教程 》——(一)脱离学习误区

本节视频连接&#xff1a; https://www.bilibili.com/video/BV1Qv411t7ae 新手C语言学习有些误区你应该知道&#xff0c;这样学习起来事半功倍~一、前言 距离上一次编写C语言的教程是5年前了&#xff08;2015年&#xff09;&#xff0c;由于自己是从初一时开始学习编程&#…

一套完整的导视设计案例_色彩导视艺术:乌克兰基辅语言学校导视设计案例

学校导视设计案例建筑师Emil Dervish为乌克兰基辅Underhub语言学校设计了色彩缤纷的导视系统&#xff0c;该设计灵感来源于伦敦地铁&#xff0c;他希望通过彩色线条的大胆应用来营造轻松而欢乐的氛围。让我们一起来看看这座由“彩虹”做导视的学校。彩虹导视设计跟着红色导视线…

C# 创建匿名管道

下面对匿名管道执行类似的操作。通过匿名管道&#xff0c;创建两个彼此通信的任务。为了给管道的创建发出信号&#xff0c;使用 ManualResetEventSlim 对象&#xff0c;与内存映射文件一样。在 Program 类的 Run 方法中&#xff0c;创建两个任务&#xff0c;调用 Reader 和 Wri…

内测投票

create table DiaoYanTiMu &#xff08;  Ids int(10) auto_increment not null primary key(),//把所需要的都写上中间不需要符号隔开&#xff0c;设自增长列类型必须是int&#xff0c;主键的话必须不能为空not null&#xff0c; Title varchar(50) not null &#xff09;;/…

Mysql 查询统计练习

2019独角兽企业重金招聘Python工程师标准>>> 1、建表 customers 顾客表 products 产品表 orders 订单表 -- 顾客表 CREATE TABLE customers (c_id INT NOT NULL AUTO_INCREMENT,lastname VARCHAR(255),firstname VARCHAR(255),address VARCHAR(255),birthday DATETI…

C++11模版元编程的应用

1.概述 关于C11模板元的基本用法和常用技巧&#xff0c;我在程序员2015年2月B《C11模版元编程》一文&#xff08;后称前文&#xff09;中已经做了详细地介绍&#xff0c;那么C11模版元编程用来解决什么实际问题呢&#xff0c;在实际工程中又该如何应用呢&#xff1f;本文将侧重…

《零基础看得懂的C语言入门教程 》——(二)C语言没那么难简单开发带你了解流程

一、学习目标 了解DevC集成开发环境了解集成开发环境了解HelloWorld程序了解HelloWorld程序的编写方法 目录 C语言真的很难吗&#xff1f;那是你没看这张图&#xff0c;化整为零轻松学习C语言。 第一篇&#xff1a;&#xff08;一&#xff09;脱离学习误区 第二篇&#xff1…

11选5下期算法_本周六周日【高二直播】辅导网课预告:通用技术电控二三极管、多用电表测量、数字逻辑电路、解析枚举递归算法,2022浙江选考技术...

01第19-21讲 2020年11月28日29日开课目录鲸学名师考点精讲系统提高高二共3阶段精品课夯实基础冲刺技术选考97-100分&#xff01;11月28日【高二|提高|直播】高二精品直播课讲授&#xff1a;浙江选考技术科目第19讲 高二综合提高鲸学名师讲授高中通用技术&#xff1a;第19讲 电控…

十分钟完成Bash 脚本进阶!列举Bash经典用法及其案例

前言&#xff1a;在linux中&#xff0c;Bash脚本是很基础的知识&#xff0c;大家可能一听脚本感觉很高大上&#xff0c;像小编当初刚开始学一样&#xff0c;感觉会写脚本的都是大神。虽然复杂的脚本是很烧脑&#xff0c;但是&#xff0c;当我们熟练的掌握了其中的用法与技巧&am…

【经典回放】多种语言系列数据结构算法:基数排序

目录 一、算法思路 二、C#语言实现 三、C语言实现 一、算法思路 1. 思想基础 基数排序的思想就是先找出待排序中的最大者&#xff0c;然后按最大者申请一个足够大的内存空间&#xff0c;并将其初始化为零&#xff0c;然后将所有待排序的数装入其中&#xff0c;标记装入的数…

探索链路追踪在.NET6工业物联网项目中的应用

如果觉得有用&#xff0c;请留言学到了。已经会了的老哥&#xff0c;请留言就这&#xff1f;可能遇到的问题工业物联网系统自上而下一般分为ERP、Mes、SCADA、WCS、边缘网关、设备等一个生产订单从SAP发送到设备要经过上述多个系统&#xff0c;当某个环节出现问题&#xff0c;可…

《零基础看得懂的C语言入门教程 》——(三)轻轻松松理解第一个C语言程序

一、学习目标 了解C语言代码的一般结构了解函数的概念了解printf函数的使用方法了解头文件的概念了解system函数的使用方法 目录 C语言真的很难吗&#xff1f;那是你没看这张图&#xff0c;化整为零轻松学习C语言。 第一篇&#xff1a;&#xff08;一&#xff09;脱离学习误…

hdu_1728_逃离迷宫(bfs)

题目连接&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid1728 题意&#xff1a;走迷宫&#xff0c;找最小的拐角 题解&#xff1a;对BFS有了新的理解&#xff0c;DFS剪枝应该也能过&#xff0c;用BFS就要以拐角作为增量来搜&#xff0c;即以当前点为坐标&#xff0c;4…

把文件放在SD卡

2019独角兽企业重金招聘Python工程师标准>>> 在程序中访问SDCard&#xff0c;你需要申请访问SDCard的权限。 在AndroidManifest.xml中加入访问SDCard的权限如下: <!-- 在SDCard中创建与删除文件权限--> <uses-permissionandroid:name"android.permiss…

如何用 windbg 导出 C# 中的 string 内容?

咨询区 driis我在用 windbg 调试一个生产上的 程序卡死 故障 &#xff0c;在线程栈上有一个 string 类型的参数相当大&#xff0c;我用 !dumpobj 命令不能正常显示内容&#xff0c;参考如下&#xff1a;0:036> !do 00000001b30d8668 Name: System.String MethodTable: 00000…

《零基础看得懂的C语言入门教程 》——(四)C语言的基本数据类型及变量

一、学习目标 了解C语言的基本数据类型了解变量的基本概念了解变量的使用方法了解了变量的命名方法了解格式占位符了解变量的输出 目录 C语言真的很难吗&#xff1f;那是你没看这张图&#xff0c;化整为零轻松学习C语言。 第一篇&#xff1a;&#xff08;一&#xff09;脱离…

转HTML+CSS总结/深入理解CSS盒子模型

原文地址&#xff1a;http://www.chinaz.com/design/2010/1229/151993.shtml 前言&#xff1a;前阵子在做一个项目时&#xff0c;在页面布局方面遇到了一点小问题&#xff0c;于是上stackoverflow上求助。ifaou在帮助我解决我问题的同时&#xff0c;还推荐我阅读一篇有关CSS盒子…

主成分分析步骤_多元分析(1)--主成分分析

主成分分析主成分分析&#xff08;PCA&#xff09;是数据降维的一种常见方法&#xff0c;其它常见的方法还有因子分析&#xff08;FA&#xff09;,独立成分分析&#xff0c;在进行大数据处理时&#xff0c;因为数据有很多特征&#xff0c;维数过高&#xff0c;不容易进行处理且…