【洛谷P3369】【模板】普通平衡树题解
【洛谷P3369】【模板】普通平衡树题解
题目链接
题意:
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
1. 插入x数
2. 删除x数(若有多个相同的数,因只删除一个)
3. 查询x数的排名(排名定义为比当前数小的数的个数+1。若有多个相同的数,因输出最小的排名)
4. 查询排名为x的数
5. 求x的前驱(前驱定义为小于x,且最大的数)
6. 求x的后继(后继定义为大于x,且最小的数)
输入格式:
第一行为n,表示操作的个数。下面n行每行有两个整数opt和x,opt表示操作的序号
输出格式:
对于操作3,4,5,6每行输出一个数,表示对应答案
样例输入:
样例输出:
时空限制:
每个测试点1s,128MB
数据范围:
n≤105
|x|≤107
1≤opt≤6
题解:
首先来讲讲什么是Treap……
Treap的中文名叫树堆(Tree+Heap),同时拥有权值和优先级;对于权值来说,它是一棵二叉搜索树(BST);对于优先级来说,它是一个堆。它可以被当作平衡树来用。
我们希望平衡树的高度尽量小,因为只有这样才能使每次操作的均摊时间复杂度趋于O(logn)。为了避免极端数据使平衡树退化为链,导致时间复杂度退化为O(n),我们可以想到用优先级来维护Treap的形态使它的高度尽量趋于平衡,因为当每个节点的权值和优先级确定时,Treap的形态是唯一确定的。我们把每个节点的优先级用随机数rand()来赋值,这样Treap就趋于平衡了。
详细代码如下(指针实现):
#include<cstdio>
#include<ctime>
#include<cstdlib>
struct node{
node*ch[];//指向左(ch[0])右(ch[1])子节点的指针
int v;//权值
int r;//优先级
int cnt;//该节点数的个数(数可以重复)
int size;//以该节点为根的子树中数的个数
node(int vv){//新建节点的构造函数
ch[]=ch[]=NULL;//两指针初始化为空指针
v=vv;//权值初始化
r=rand();//优先级用随机数初始化
cnt=size=;//只含一个数
}
};
node*super;//指向整棵Treap的大根的指针
int n,ans;
inline void maintain(node*p){//维护该节点的附加信息
p->size=p->cnt;
if(p->ch[]!=NULL)p->size+=p->ch[]->size;
if(p->ch[]!=NULL)p->size+=p->ch[]->size;
}
inline void rot(node*&p,int lr){//旋转操作(lr==0:左旋,lr==1:右旋)
node*k=p->ch[lr^];
p->ch[lr^]=k->ch[lr];
k->ch[lr]=p;
p=k;
}
void ins(node*&p,int val){//插入操作:在以p为根的子树中插入一个val数
if(p==NULL){//空节点直接建新点
p=new node(val);
}else if(val==p->v){//找到了已经存在的节点
p->cnt++;
p->size++;
}else if(val<p->v){
ins(p->ch[],val);//在左子节点中插入
if(p->ch[]->r<p->r){//维护优先级(小根堆)
rot(p,);
maintain(p->ch[]);
}
maintain(p);
}else{
ins(p->ch[],val);//在右子节点中插入
if(p->ch[]->r<p->r){
rot(p,);
maintain(p->ch[]);
}
maintain(p);
}
}
void del(node*&p,int val){//删除操作:在以p为根的子树中删除一个val数
if(val<p->v){
del(p->ch[],val);
maintain(p);
}else if(val>p->v){
del(p->ch[],val);
maintain(p);
}else{
if(p->cnt>){//该节点包含多个数,直接减即可
p->cnt--;
p->size--;
}else{//删除该节点
if(p->ch[]!=NULL){
if(p->ch[]!=NULL){//该节点有左右子节点
int lr=p->ch[]->r<p->ch[]->r?:;//选优先级小的子节点为根(小根堆)
rot(p,lr^);//旋转
del(p->ch[lr^],val);//递归向下删除
maintain(p);//递归返回向上维护
}else{//无右子节点
node*pp=p;
p=p->ch[];
delete pp;
}
}else{//无左子节点
if(p->ch[]!=NULL){
node*pp=p;
p=p->ch[];
delete pp;
}else{//都无
delete p;
p=NULL;
}
}
}
}
}
int qrank(node*p,int val){//当前以p为根的子树中小于val的数的个数+1
int ssl=p->ch[]==NULL?:p->ch[]->size;//该子树中小于val的数的个数
if(val==p->v)return ssl+;
else if(val<p->v){
if(p->ch[]!=NULL)return qrank(p->ch[],val);
else return ;
}else{
if(p->ch[]!=NULL)return ssl+p->cnt+qrank(p->ch[],val);
else return p->size+;
}
}
int qval(node*p,int rank){//在当前子树中查找排名为rank的数
int ssl=p->ch[]==NULL?:p->ch[]->size;
if(rank<=ssl)return qval(p->ch[],rank);
else if(rank<=ssl+p->cnt)return p->v;
else return qval(p->ch[],rank-ssl-p->cnt);
}
void pred(node*p,int val){//在当前子树中查找val的前驱
if(val<=p->v){
if(p->ch[]!=NULL)pred(p->ch[],val);
}else{
ans=p->v;//ans为暂定的答案,当ans无法再修改时,ans为最终答案
if(p->ch[]!=NULL)pred(p->ch[],val);
}
}
void succ(node*p,int val){
if(val>=p->v){
if(p->ch[]!=NULL)succ(p->ch[],val);
}else{
ans=p->v;
if(p->ch[]!=NULL)succ(p->ch[],val);
}
}
int main(){
srand(time());//初始化随机数种子
scanf("%d",&n);
while(n--){
int opt,x;
scanf("%d%d",&opt,&x);
switch(opt){
case :{
ins(super,x);
break;
}
case :{
del(super,x);
break;
}
case :{
printf("%d\n",qrank(super,x));
break;
}
case :{
printf("%d\n",qval(super,x));
break;
}
case :{
pred(super,x);
printf("%d\n",ans);
break;
}
case :{
succ(super,x);
printf("%d\n",ans);
break;
}
}
}
return ;
}
【洛谷P3369】【模板】普通平衡树题解的更多相关文章
- 【洛谷P3369】普通平衡树——Splay学习笔记(一)
二叉搜索树(二叉排序树) 概念:一棵树,若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值: 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值: 它的左.右子树也分别为二叉搜索树 ...
- 洛谷.3369.[模板]普通平衡树(Splay)
题目链接 第一次写(2017.11.7): #include<cstdio> #include<cctype> using namespace std; const int N ...
- 洛谷.3369.[模板]普通平衡树(fhq Treap)
题目链接 第一次(2017.12.24): #include<cstdio> #include<cctype> #include<algorithm> //#def ...
- 洛谷.3391.[模板]文艺平衡树(Splay)
题目链接 //注意建树 #include<cstdio> #include<algorithm> const int N=1e5+5; //using std::swap; i ...
- 洛谷P3369 【模板】普通平衡树(Treap/SBT)
洛谷P3369 [模板]普通平衡树(Treap/SBT) 平衡树,一种其妙的数据结构 题目传送门 题目描述 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作: 插入x数 删除 ...
- 洛谷P3369普通平衡树(Treap)
题目传送门 转载自https://www.cnblogs.com/fengzhiyuan/articles/7994428.html,转载请注明出处 Treap 简介 Treap 是一种二叉查找树.它 ...
- 洛谷P1783 海滩防御 分析+题解代码
洛谷P1783 海滩防御 分析+题解代码 题目描述: WLP同学最近迷上了一款网络联机对战游戏(终于知道为毛JOHNKRAM每天刷洛谷效率那么低了),但是他却为了这个游戏很苦恼,因为他在海边的造船厂和 ...
- 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)
To 洛谷.3373 [模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格 ...
- 洛谷P4047 [JSOI2010]部落划分题解
洛谷P4047 [JSOI2010]部落划分题解 题目描述 聪聪研究发现,荒岛野人总是过着群居的生活,但是,并不是整个荒岛上的所有野人都属于同一个部落,野人们总是拉帮结派形成属于自己的部落,不同的部落 ...
随机推荐
- Java框架spring 学习笔记(十六):c3p0连接池的配置以及dao使用jdbcTemplate
连接池可以大大提高数据库的性能和连接速度,将那些已连接的数据库连接存放在一个连接池里,以后别人要连接数据库的时候,将不会重新建立数据库连接,直接从连接池中取出可用的连接,用户使用完毕后,会释放连接重新 ...
- 数字证书原理(ssl,https)
文中首先解释了加密解密的一些基础知识和概念,然后通过一个加密通信过程的例子说明了加密算法的作用,以及数字证书的出现所起的作用.接着对数字证书做一个详细的解释,并讨论一下windows中数字证书的管理, ...
- cocoapods 安装中出的太多问题
前言: 新欢的公司,新买的电脑,新安装 cocoapods.然后开开心心去百度如何安装 cocoapods,前面的步骤我就不说了. 在 pod setup 上之后,网速超慢然后就失败 fatal: T ...
- linux下搭建Jenkins环境
前提:Tomcat.jdk已安装并配置成功,具体安装和配置可参考我的其他随笔,在此不再详述 1.官网下载Jenkins最新war包,jenkins.war 2.进入Tomcat安装目录,创建Jenki ...
- Tigase8.0 源代码分析:一、启动篇
Tigase8.0 引用了IoC(控制反转)和DI(依赖注入) 等技术手段,来对对象的创建和控制.不懂的百度下就知道了,Spring完美的实现IOC ,贴一段解释: 通俗地说:控制反转IoC(Inve ...
- 原生js简单轮播图 代码
在团队带人,突然被人问到轮播图如何实现,进入前端领域有一年多了,但很久没自己写过,一直是用大牛写的插件,今天就写个简单的适合入门者学习的小教程.当然,轮播图的实现原理与设计模式有很多种,我这里讲的是用 ...
- weex h5开发区别-实践初级篇
html标签 weex中没有标签的概念,html中标签对应于weex中的Components weex 无<span> .<p> ,用<text>替代.但是< ...
- Win10配置ADB工具教程
1.在该网站下载adb工具 http://pcedu.pconline.com.cn/748/7481463.html 2. Win10怎么配置ADB环境?Win10怎么安装ADB工具?这想必是很多安 ...
- sort 对多列进行排序
sort -t '\t' -k 3,3 -k 2,2 文件名 # 先对第三列进行排序,然后再对第二列进行排序
- 密码与安全新技术专题之WEB应用安全
学号 2018-2019-2 <密码与安全新技术专题>第1周作业 课程:<密码与安全新技术专题> 班级: 1892 姓名: 李熹桥 学号:20189214 上课教师:谢四江 上 ...