初识Treap
Treap,简单的来说就是Tree+Heap,是一颗平衡树,每个节点有两个信息:1.key:当前节点的关键字 ;2.fix:当前节点优先级。key满足二叉排序数的性质,即左儿子都比当前节点小,右儿子都比当前节点大(或相等),fix是一个随机的数,满足小根堆(或大根堆)的性质,fix是为了防止Treap退化成链表的简单优化策略。
如下面的一颗Treap:
Treap可以进行下面几种操作:插入,查询第k大,旋转,还有其他一些基本操作和一些高级的操作,这里暂不作介绍。
1.插入元素
Treap的关联形式是链表,所以要定义一个结构体,其中包含一个指向Treap类型的指针,树的大小,左右儿子的指针。
- struct Treap
- {
- int size,key,fix;
- Treap *ch[2];
- Treap(int k)//构造函数
- {
- size=1;
- fix=rand();
- key=k;
- ch[0]=ch[1]=NULL;
- }
- int compare(int x)const
- {
- return key==x?-1:x<key?0:1;
- }
- void Maintain() //计算Treap的大小
- {
- size=1;
- if(ch[0]!=NULL)size+=ch[0]->size;
- if(ch[1]!=NULL)size+=ch[1]->size;
- }
- };
插入的时候,如果当前元素是空的,就用new运算符构造一颗新树(没有儿子节点),如果不是空的,就递归向下直到是 叶子节点。节点之间的联系是以链表的形式建立起来的。
如果新插入的元素的优先级不满足小根堆的性质,则要进行旋转操作,使优先级满足要求。
- void insert(Treap *&t,int x)
- {
- if(t==NULL)t=new Treap(x);
- else
- {
- int d=x < t->key?0:1;
- insert(t->ch[d],x);
- if(t->fix > t->ch[d]->fix) //破坏了优先级顺序
- Rotate(t,d);
- }
- t->Maintain();
- }
2.旋转
当优先级破坏了小根堆的性质的时候,就要进行旋转操作,使重新满足小根堆。
旋转的时候有两种情况
①:左左旋转
②:右右旋转
两种情况可以综合到一起,详细见代码。
- void Rotate(Treap *&t,int d)
- {
- Treap *k=t->ch[d]; //临时变量
- t->ch[d]=k->ch[d^1]; //用要旋转的节点的“反”儿子替换它的位置
- k->ch[d^1]=t; //旋转上去
- t->Maintain(); //先计算t的大小,因为现在t是k的子节点。
- k->Maintain();
- t=k; //根节点上移
- }
这里参数的含义是,要处理的根节点是t,ch[d]需要旋转。将参数定义成指针的引用是为了方便修改t的地址。
3.查找第K大元素
利用Treap的二叉排序树的性质,左儿子都小于根节点,右儿子大于等于根节点,即可找出第K大元素。
- int Kth(Treap*t,int k)
- {
- if(t==NULL || k<=0 || t->size<k)return -1; //找不到
- if(t->ch[0]==NULL && k==1)return t->key; //是当前值
- if(t->ch[0]==NULL)return Kth(t->ch[1],k-1); //在右子树找,注意要先出去根节点,所以是k-1
- if(t->ch[0]->size >=k )return Kth(t->ch[0],k); //在左子树找,因为左子树上的值都小于当前节点,所以仍然是查找第K大
- if(t->ch[0]->size+1==k)return t->key;
- return Kth(t->ch[1],k-1-t->ch[0]->size); //注意这里k要减1
- }
4.删除Treap
为了减小空间的占用,在使用完了Treap之后,要及时的把它删掉,因为是链表,所以只能一个一个的删除。
- void DeleteTreap(Treap*&t)
- {
- if(t==NULL)return;
- if(t->ch[0]!=NULL)DeleteTreap(t->ch[0]); //删除左子树
- if(t->ch[1]!=NULL)DeleteTreap(t->ch[1]); //删除右子树
- delete t; //释放内存
- t=NULL;
- }
题目大意:给n个数,m个查询,每次查询前x个数里面第k大的数,x是升序排列的。
- #include<iostream>
- #include<cstdio>
- #include<algorithm>
- #include<cstdlib>
- #include<string>
- #define rep(i,n) for(i=1;i<=n;++i)
- using namespace std;
- const int maxn=1000005;
- int n,m,val[maxn];
- struct Treap
- {
- int size,key,fix;
- Treap *ch[2];
- Treap(int k)
- {
- size=1;
- fix=rand();
- key=k;
- ch[0]=ch[1]=NULL;
- }
- int compare(int x)const
- {
- return key==x?-1:x<key?0:1;
- }
- void Maintain()
- {
- size=1;
- if(ch[0]!=NULL)size+=ch[0]->size;
- if(ch[1]!=NULL)size+=ch[1]->size;
- }
- };
- void Rotate(Treap *&t,int d)
- {
- Treap *k=t->ch[d];
- t->ch[d]=k->ch[d^1];
- k->ch[d^1]=t;
- t->Maintain();
- k->Maintain();
- t=k;
- }
- void insert(Treap *&t,int x)
- {
- if(t==NULL)t=new Treap(x);
- else
- {
- int d=x < t->key?0:1;
- insert(t->ch[d],x);
- if(t->fix > t->ch[d]->fix)
- Rotate(t,d);
- }
- t->Maintain();
- }
- int Kth(Treap*t,int k)
- {
- if(t==NULL || k<=0 || t->size<k)return -1;
- if(t->ch[0]==NULL && k==1)return t->key;
- if(t->ch[0]==NULL)return Kth(t->ch[1],k-1);
- if(t->ch[0]->size >=k )return Kth(t->ch[0],k);
- if(t->ch[0]->size+1==k)return t->key;
- return Kth(t->ch[1],k-1-t->ch[0]->size);
- }
- void DeleteTreap(Treap*&t)
- {
- if(t==NULL)return;
- if(t->ch[0]!=NULL)DeleteTreap(t->ch[0]);
- if(t->ch[1]!=NULL)DeleteTreap(t->ch[1]);
- delete t;
- t=NULL;
- }
- int main()
- {
- // freopen("A.in","r",stdin);
- // freopen("A.out","w",stdout);
- while(scanf("%d%d",&n,&m)!=EOF)
- {
- int i,index=1,j;
- rep(i,n)scanf("%d",&val[i]);
- Treap *root=NULL;
- rep(i,m)
- {
- int p;
- scanf("%d",&p);
- for(j=index;j<=p;j++)
- insert(root,val[j]);
- index=p+1; //更新index
- printf("%d\n",Kth(root,i));
- }
- DeleteTreap(root); //删除Treap
- }
- return 0;
- }
初识Treap的更多相关文章
- Treap详解
今天一天怼了平衡树.深深地被她的魅力折服了.我算是领略到了高级数据结构的美妙.oi太神奇了. 今天初识平衡树,选择了Treap. Treap又叫树堆,是一个二叉搜索树.我们知道,它的节点插入是随机的, ...
- 入门平衡树: Treap
入门平衡树:\(treap\) 前言: 如有任何错误和其他问题,请联系我 微信/QQ同号:615863087 前置知识: 二叉树基础知识,即简单的图论知识. 初识\(BST\): \(BST\)是\( ...
- fhq treap最终模板
新学习了fhq treap,厉害了 先贴个神犇的版, from memphis /* Treap[Merge,Split] by Memphis */ #include<cstdio> # ...
- Android动画效果之初识Property Animation(属性动画)
前言: 前面两篇介绍了Android的Tween Animation(补间动画) Android动画效果之Tween Animation(补间动画).Frame Animation(逐帧动画)Andr ...
- 初识Hadoop
第一部分: 初识Hadoop 一. 谁说大象不能跳舞 业务数据越来越多,用关系型数据库来存储和处理数据越来越感觉吃力,一个查询或者一个导出,要执行很长 ...
- python学习笔记(基础四:模块初识、pyc和PyCodeObject是什么)
一.模块初识(一) 模块,也叫库.库有标准库第三方库. 注意事项:文件名不能和导入的模块名相同 1. sys模块 import sys print(sys.path) #打印环境变量 print(sy ...
- 初识IOS,Label控件的应用。
初识IOS,Label控件的应用. // // ViewController.m // Gua.test // // Created by 郭美男 on 16/5/31. // Copyright © ...
- UI篇(初识君面)
我们的APP要想吸引用户,就要把UI(脸蛋)搞漂亮一点.毕竟好的外貌是增进人际关系的第一步,我们程序员看到一个APP时,第一眼就是看这个软件的功能,不去关心界面是否漂亮,看到好的程序会说"我 ...
- Python导出Excel为Lua/Json/Xml实例教程(一):初识Python
Python导出Excel为Lua/Json/Xml实例教程(一):初识Python 相关链接: Python导出Excel为Lua/Json/Xml实例教程(一):初识Python Python导出 ...
随机推荐
- hdu 1263 水果
Problem Description 夏天来了~~好开心啊,呵呵,好多好多水果~~ Joe经营着一个不大的水果店.他认为生存之道就是经营最受顾客欢迎的水果.现在他想要一份水果销售情况的明细表,这样J ...
- 织梦dedecms自定义字段在首页列表页文章页的调用
1.首页调用. {dede:arclist addfields='字段英文名' channelid='模型ID' row='条数' type='栏目ID'} [field:字段英文名/ ...
- NAS4Free 安装配置(五)配置SMB
配置SMB 现在我们有2块存储设备,一块做下载盘,一块做数据盘 为了便于管理和扩展,我们分别在两块盘上建文件夹和Dataset 对于download盘,因为是UFS,所以只能建文件夹 我们把整个盘共享 ...
- 字符串:各种奇葩的内置方法 - 零基础入门学习Python014
字符串:各种奇葩的内置方法 让编程改变世界 Change the world by program 字符串:各种奇葩的内置方法 或许现在又回过头来谈字符串,有些朋友可能会觉得没必要,也有些朋友会觉得不 ...
- R教程计划
提起数据挖掘,似乎会有很多人望而却步,从生产规划到到规律分析,从生物医学到航天科技,到处都有数据挖掘工程师留下的影子. 通过对比SAS,SPSS,以及R,最终选定了R, 不为什么,免费且高效才是硬道理 ...
- Android手机配置gcc,实现手机编译代码
1.下载gcc.zip 2.把gcc.zip解压存放在/data目录下(也可以是其他目录,看个人习惯) 3.配置gcc环境变量 export GCCHOME=/data/gcc (gcc存放路径) e ...
- php爬虫的两种思路
写php爬虫可能最大的问题就是php脚本执行时间的问题了,对于这个问题,我找到了两种解决方法. 第一种通过代码set_time_limit(0)或者ini_set("max_executio ...
- Tomcat 6.0.32 +Spring dbcp datasource关闭Tomcat出现严重异常
异常如下: 信息: Pausing Coyote HTTP/ -- :: org.apache.catalina.core.StandardService stop 信息: Stopping serv ...
- hdu 1245 Saving James Bond
http://acm.hdu.edu.cn/showproblem.php?pid=1245 #include <cstdio> #include <cstring> #inc ...
- c++ 14
一.堆栈(stack) stack -> vector/deque/list push -> push_back pop -> pop_back top -> bac ...