模板——Treap
不得不说平衡树博大精深,除了Treap,还有splay,非旋Treap和可持久化数据结构,今天先讲讲Treap,也很感谢这位大佬的博客给予我帮助:http://www.360doc.com/content/19/0120/11/5315_810146183.shtml
Treap的核心就是Tree+Heap,即在二叉搜索树的基础上根据随机数生成的优先级使树保持堆的性质,从而实现使Treap的深度不会太大的效果
核心操作就是旋转:人工YY一下……发现旋转有左旋(Zag)和右旋(Zig)两种操作,旋转时连三条边,即原顶点和新儿子的边,新定点作为原顶点父亲的边,以及上一级父亲连向新顶点的边。顶点和儿子连接的边先处理,用&p始终维护顶点坐标,因为传入的是son[father[p]],所以p变化时它父亲的儿子会自动变化,所以通过取址可以自动连边 (rotate下一层的p是上一层的son,p变上一层son就变) (详见代码)
除了insert和delete操作中需要rotate(delete要把删除点转到叶子结点再删去,insert在插入后要旋转以维护heap的性质,不要忘记操作之后要push_up),其它的代码都和二叉搜索树一样
// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=;
const int N=;
const int inf=(int)2e9;
int R=; int ran()
{
static ll seed=;
seed=seed*%mod;
return (int)seed;
} struct node
{
int rnd,val,sz,ch[],num;
node(){}
node(int val,int sz,int num):val(val),sz(sz),num(num){
rnd=ran();//大根堆
ch[]=ch[]=;//和上方函数不能同时使用,若去掉该句会MLE
}
}a[];
int sum_node=;//同一节点内的相同数字的个数 void push_up(int x)
{
a[x].sz=a[x].num+a[a[x].ch[]].sz+a[a[x].ch[]].sz;
} void rotate(int &p,int d)//0:Zag 1:Zig
{
int k=a[p].ch[d^];
a[p].ch[d^]=a[k].ch[d];
a[k].ch[d]=p;
push_up(p);
push_up(k);
p=k;//传入的是son[father],father连边自动变
} void insert(int &p,int x)
{
if(!p)
{
p=++sum_node;
node tmp(x,,);
a[p]=tmp;
return;
}
if(a[p].val==x)
{
a[p].num++;
a[p].sz++;
return;
}
int d=(int)(x>a[p].val);
insert(a[p].ch[d],x);
if(a[p].rnd<a[a[p].ch[d]].rnd) rotate(p,d^);//大根堆
//本一级rotate传入的p就是上一级insert传入的son
push_up(p);
return;
} void del(int &p,int x)
{
if(!p) return;
if(a[p].val>x) del(a[p].ch[],x);
else if(a[p].val<x) del(a[p].ch[],x);
else
{
if(!a[p].ch[]&&!a[p].ch[])
{
a[p].num--; a[p].sz--;
if(a[p].num==) p=;
}
else if(a[p].ch[]&&!a[p].ch[])
{
rotate(p,);
del(a[p].ch[],x);
}
else if(!a[p].ch[]&&a[p].ch[])
{
rotate(p,);
del(a[p].ch[],x);//之前写反了
}
else
{
int d=(int)(a[a[p].ch[]].rnd>a[a[p].ch[]].rnd);
rotate(p,d);
del(a[p].ch[d],x);
}
}
push_up(p);
} int rnk(int p,int x)//以p为根的x的rank
{
if(p==) return ;//important
if(x>a[p].val)
{
return a[a[p].ch[]].sz+a[p].num+rnk(a[p].ch[],x);
}
else if(x<a[p].val)
{
return rnk(a[p].ch[],x);
}
else
{
return a[a[p].ch[]].sz+;
}
} int find(int p,int x)//已知rank查数
{
if(!p) return ;
if(a[a[p].ch[]].sz+a[p].num<x)//important(num)
{
return find(a[p].ch[],x-a[a[p].ch[]].sz-a[p].num);
}
else if(a[a[p].ch[]].sz>=x)//>=!!!
{
return find(a[p].ch[],x);
}
else
{
return a[p].val;
}
} int pre(int p,int x)
{
if(!p) return -inf;
if(a[p].val>=x)
{
return pre(a[p].ch[],x);
}
else return max(a[p].val,pre(a[p].ch[],x));
} int suc(int p,int x)
{
if(!p) return inf;
if(a[p].val<=x)
{
return suc(a[p].ch[],x);
}
else return min(a[p].val,suc(a[p].ch[],x));
} int n;
int main()
{
scanf("%d",&n);
for(int i=;i<=n;i++)
{
int opt,x;
scanf("%d%d",&opt,&x);
if(opt==) insert(R,x);//R每次会随着p改变
else if(opt==) del(R,x);
else if(opt==) printf("%d\n",rnk(R,x));
else if(opt==) printf("%d\n",find(R,x));
else if(opt==) printf("%d\n",pre(R,x));
else printf("%d\n",suc(R,x));
}
return ;
}
模板——Treap的更多相关文章
- [模板] Treap
插入x 删除x 查询排名为x的数 查询x的排名 求x的前驱.后继 //Stay foolish,stay hungry,stay young,stay simple #include<iostr ...
- 模板—treap
#include<iostream> #include<cstdio> #include<cstdlib> #define INF 0x7fffffff using ...
- 模板——Treap实现名次树
Treap 是一种通过赋予结点随机权值的一种满足堆性质的二叉搜索树,它很好的解决了二叉搜索树顺序插入组成链式的局限性. 名次树是指在treap的每个结点中添加附加域size,表示以它为根的子树的总结点 ...
- LG3369 普通平衡树
题意 维护一些数,其中需要提供以下操作: 1.插入\(x\) 2.删除\(x\)(若有多个相同的数,只删除一个) 3.查询\(x\)的排名(排名定义为比当前数小的数的个数\(+1\)) 4.查询排名为 ...
- treap树模板
///treap树模板 typedef struct Node ///节点的结构体 { Node *l,*r; int val,pri; ///节点的值和优先级 int sz; ///节点子树的节点数 ...
- BZOJ 3224 TYVJ 1728 普通平衡树 [Treap树模板]
3224: Tyvj 1728 普通平衡树 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 7390 Solved: 3122 [Submit][S ...
- 三大平衡树(Treap + Splay + SBT)总结+模板[转]
Treap树 核心是 利用随机数的二叉排序树的各种操作复杂度平均为O(lgn) Treap模板: #include <cstdio> #include <cstring> #i ...
- treap完全版模板
这是我综合poj1442 3481 2352的treap操作 得到treap完全版模板.(经测AC) 结构体Tree { int key; //键值 int size; //该子树总节点个数 int ...
- Treap 模板 poj1442&hdu4557
原理可以看hihocoder上面的讲解,很清楚,不多说了. 模板抄lrj训练指南上面的. /** Treap 实现 名次树 功能: 1.找到排名为k的元素 2.值为x的元素的名次 初始化:Node* ...
随机推荐
- 【洛谷】P1009阶乘之和
题目链接:https://www.luogu.org/problemnew/show/P1009 题意:给一个整数n(n<50),求$ \sum^{n}_{i=1} i! $ 题解:我..拿py ...
- Mybatis 使用Mapper接口的Sql动态代码方式进行CURD和分页查询
1.Maven的pom.xml 2.配置文件 2.1.db.properties 2.2.mybatis.xml 2.3.log4j.xml 3.MybatisUtil工具类 4.Mapper映射文件 ...
- OC和Cocos-js的互相调用
OC调用cocos-js #import "ScriptingCore.h" #import "cocos2d.h" #include "script ...
- Linux 实用指令(9)--进程管理
目录 进程管理 1 进程的基本介绍 2 显示系统执行的进程 2.1 说明: 2.2 ps指令详解 2.3 应用实例 3 终止进程kill和killall 3.1 介绍 3.2 基本语法 3.3 常用选 ...
- 阿里云SaaS加速器“宜搭”发布宜搭Plus提升6倍研发效率
9月26日,在杭州云栖大会上,阿里云SaaS加速器的“底座”——“宜搭”正式发布“宜搭Plus”低代码开发平台.开发复杂企业业务系统所需要的领域数据模型.逻辑&服务编排.专业UI页面设计等,都 ...
- thinkphp 规则路由
规则路由是一种比较容易理解的路由定义方式,采用ThinkPHP设计的规则表达式来定义. 规则表达式 规则表达式通常包含静态地址和动态地址,或者两种地址的结合,例如下面都属于有效的规则表达式: 'my' ...
- jdk配置到tomcat配置
1.jdk配置 首先下载jdk 这里我下载的是 jdk1.8 (jdk1.8.0_181\) 然后,安装 我的安装路径 C:\Program Files\Java\jdk1.8.0_181\ 我选择默 ...
- 初步了解Redis
参考: https://juejin.im/post/5b4dd82ee51d451925629622?utm_source=gold_browser_extension https://www.cn ...
- Oracle Spatial导入shp数据
现在开始尝试用oracle spatial管理空间数据,刚学会shp数据的导入,总结如下.oracle11g安装后,已经有了oracle spatial组件,我们只需要用shp2sdo.exe工具,就 ...
- django2 rest api
版本django 2.2.3,我用的社区版 1.安装django:pycharm——Settings——Project Interpreter——选择你要的Python解释器版本——点击右侧的加号,输 ...