fhq treap——简单又好写的数据结构
今天上午学了一下fhq treap感觉真的很好用啊qwq
- 变量名解释:
- \(size[i]\)表示以该节点为根的子树大小
- \(fix[i]\)表示随机权值
- \(val[i]\)表示该节点的值
- \(ch[i][0]\)表示该节点的左儿子
- \(ch[i][1]\)表示该节点的右儿子
- 更新操作:update
inline void update(int x)
{size[x]=1+size[ch[x][0]]+size[ch[x][1]];}
就是用自己的左右子树更新自己。
- 新建节点:new_node
inline int new_node(int x)
{
size[++cnt]=1;
val[cnt]=x;
fix[cnt]=rand();
return cnt;
}
- 分裂操作:split
inline void split(int now,int k,int &x,int &y)
{
if(!now) x=y=0;
else
{
if(val[now]<=k) x=now,split(ch[now][1],k,ch[now][1],y);
else y=now,split(ch[now][0],k,x,ch[now][0]);
update(now);
}
}
x,y分别表示左右子树的根节点。
刚开始肯定是要初始化为0的。
之后因为分裂之后now这个点是在左子树里面的,所以如果val[now]<=k的话,当前点的左子树肯定要归到左子树里,但是右子树里的点不确定,递归求解右子树。
val[now]>k的话道理相似。
- 合并操作:merge
inline int merge(int A,int B)
{
if(!A||!B) return A+B;
if(fix[A]<fix[B])
{
ch[A][1]=merge(ch[A][1],B);
update(A);
return A;
}
else
{
ch[B][0]=merge(A,ch[B][0]);
update(B);
return B;
}
}
返回值是合并之后树的根节点。
我们比较他们的随机权值,如果B大,就把A的右子树和B进行合并。如果A大,就把A和B的左子树进行合并。
注意因为传入参数的时候A这棵树的权值默认是小于B的,所以顺序不要写反了qwq.......
- 求一棵树\((now)\)中排名第\(k\)个的数的节点编号:kth
inline int kth(int now,int k)
{
while(1)
{
if(k<=size[ch[now][0]]) now=ch[now][0];
else if(k==size[ch[now][0]]+1) return now;
else k-=size[ch[now][0]]+1,now=ch[now][1];
}
}
- 求k的全局排名:rnk
inline int rnk(int a)
{
split(root,a-1,x,y);
int res=size[x]+1;
root=merge(x,y);
return res;
}
- 插入节点:in
inline void in(int a)
{
split(root,a,x,y);
root=merge(merge(x,new_node(a)),y);
}
- 删除节点:del
inline void del(int a)
{
split(root,a,x,z);
split(x,a-1,x,y);
y=merge(ch[y][0],ch[y][1]);
root=merge(merge(x,y),z);
}
- 求前驱: pre
inline int pre(int a)
{
split(root,a-1,x,y);
int res=val[kth(x,size[x])];
root=merge(x,y);
return res;
}
分裂之后很明显x中都小于等于a,求前继的话就可以直接输出x中最大数了。
- 求后继: nxt
inline int nxt(int a)
{
split(root,a,x,y);
int res=val[kth(y,1)];
root=merge(x,y);
return res;
}
分裂之后y中的都大于a,所以直接输出y中的第一个就可以了qwq
最后以一个普通平衡树的模板AC代码来结尾吧。。。
代码对fhq封装了一下qwq
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<ctime>
inline int read(){
int x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
namespace fhq
{
#define MAXN 500010
int x,y,z,root,cnt;
int size[MAXN],val[MAXN],ch[MAXN][2],fix[MAXN];
inline void update(int x){size[x]=1+size[ch[x][0]]+size[ch[x][1]];}
inline int new_node(int x){size[++cnt]=1;val[cnt]=x;fix[cnt]=rand();return cnt;}
inline int merge(int A,int B)
{
if(!A||!B) return A+B;
if(fix[A]<fix[B]){ch[A][1]=merge(ch[A][1],B);update(A);return A;}
else {ch[B][0]=merge(A,ch[B][0]);update(B);return B;}
}
inline void split(int now,int k,int &x,int &y)
{
if(!now) x=y=0;
else{
if(val[now]<=k) x=now,split(ch[now][1],k,ch[now][1],y);
else y=now,split(ch[now][0],k,x,ch[now][0]);
update(now);
}
}
inline int kth(int now,int k){while(1){
if(k<=size[ch[now][0]]) now=ch[now][0];
else if(k==size[ch[now][0]]+1) return now;
else k-=size[ch[now][0]]+1,now=ch[now][1];}
}
inline int rnk(int a){split(root,a-1,x,y);int res=size[x]+1;root=merge(x,y); return res;}
inline void in(int a){split(root,a,x,y);root=merge(merge(x,new_node(a)),y);}
inline void del(int a){split(root,a,x,z);split(x,a-1,x,y);y=merge(ch[y][0],ch[y][1]);root=merge(merge(x,y),z);}
inline int pre(int a){split(root,a-1,x,y);int res=val[kth(x,size[x])];root=merge(x,y);return res;}
inline int nxt(int a){split(root,a,x,y);int res=val[kth(y,1)];root=merge(x,y);return res;}
}
using namespace std;
using namespace fhq;
int T,cur,p;
int main()
{
srand(time(NULL));
T=read();
while(T--)
{
p=read(),cur=read();
if(p==1) fhq::in(cur);
else if(p==2) del(cur);
else if(p==3) printf("%d\n",fhq::rnk(cur));
else if(p==4) printf("%d\n",fhq::val[kth(root,cur)]);
else if(p==5) printf("%d\n",fhq::pre(cur));
else if(p==6) printf("%d\n",fhq::nxt(cur));
}
return 0;
}
哦,对了用fhq如果rp好的话还可以过掉NOIP2017列队。。。。可以尝试一下qwq
fhq treap——简单又好写的数据结构的更多相关文章
- 【POJ2761】【fhq treap】A Simple Problem with Integers
Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. On ...
- 【数据结构】FHQ Treap详解
FHQ Treap是什么? FHQ Treap,又名无旋Treap,是一种不需要旋转的平衡树,是范浩强基于Treap发明的.FHQ Treap具有代码短,易理解,速度快的优点.(当然跟红黑树比一下就是 ...
- FHQ Treap小结(神级数据结构!)
首先说一下, 这个东西可以搞一切bst,treap,splay所能搞的东西 pre 今天心血来潮, 想搞一搞平衡树, 先百度了一下平衡树,发现正宗的平衡树写法应该是在二叉查找树的基础上加什么左左左右右 ...
- 【数据结构】平衡树splay和fhq—treap
1.BST二叉搜索树 顾名思义,它是一棵二叉树. 它满足一个性质:每一个节点的权值大于它的左儿子,小于它的右儿子. 当然不只上面那两种树的结构. 那么根据性质,可以得到该节点左子树里的所有值都比它小, ...
- 在平衡树的海洋中畅游(四)——FHQ Treap
Preface 关于那些比较基础的平衡树我想我之前已经介绍的已经挺多了. 但是像Treap,Splay这样的旋转平衡树码亮太大,而像替罪羊树这样的重量平衡树却没有什么实际意义. 然而类似于SBT,AV ...
- BZOJ3159: 决战(FHQ Treap)
传送门: 解题思路: 算是补坑了,这题除了Invert以外就可以树剖线段树解决了. 考虑Invert操作,延续先前树链剖分的做法,考虑先前算法的瓶颈. 最暴力的方法是暴力交换权值,然而这种方法忽略了当 ...
- 可持久化treap(FHQ treap)
FHQ treap 的整理 treap = tree + heap,即同时满足二叉搜索树和堆的性质. 为了使树尽可能的保证两边的大小平衡,所以有一个key值,使他满足堆得性质,来维护树的平衡,key值 ...
- 并不对劲的fhq treap
听说很对劲的太刀流不止会splay一种平衡树,并不对劲的片手流为了反驳他,并与之针锋相对,决定学学高端操作. 很对劲的太刀流-> 据说splay常数极大,但是由于只知道splay一种平衡树能对序 ...
- FHQ treap学习(复习)笔记
.....好吧....最后一篇学习笔记的flag它倒了..... 好吧,这篇笔记也鸽了好久好久了... 比赛前刷模板,才想着还是补个坑吧... FHQ,这个神仙(范浩强大佬),发明了这个神仙的数据结构 ...
随机推荐
- 并发编程之IO模型比较和Selectors模块
主要内容: 一.IO模型比较分析 二.selectors模块 1️⃣ IO模型比较分析 1.前情回顾: 上一小节中,我们已经分别介绍过了IO模型的四个模块,那么我想大多数都会和我一样好奇, 阻塞IO和 ...
- Lamber算法 & SurfaceShader自定义光照
[SurfaceShader自定义光照] 1.在pragma中添加自定义光照函数名: #pragma surface surf BasicDiffuse 2.实现自定义光照函数.下面就是Lamber ...
- mybatis+oracle如何批量执行多条update
接口 public void setStatus(List<Columns> columnsList); mapping xmlmapping 中使用foreach,关于标签的使用,资料非 ...
- 小程序本地资源无法通过 css 获取
background-image:可以使用网络图片,或者 base64,或者使用<image/>标签
- Linux安装MySQL全过程
操作系统:CentOS 7.2 64位 mySQL版本:mysql-5.6.35 安装过程: (1)首先从mysql官网下载 MySQL Community Server 安装包. 选择对应的版本( ...
- 410. Split Array Largest Sum 把数组划分为m组,怎样使最大和最小
[抄题]: Given an array which consists of non-negative integers and an integer m, you can split the arr ...
- Sed命令n,N,d,D,p,P,h,H,g,G,x解析3
摘自:https://blog.csdn.net/WMSOK/article/details/78463199 Sed命令n,N,d,D,p,P,h,H,g,G,x解析 2017年11月06日 23: ...
- nuget get-package id显示不全
Get-Package | ft -AutoSize 参考 https://stackoverflow.com/questions/5036719/is-there-a-way-to-get-the- ...
- mysql 空间索引的使用
CREATE TABLE tb_geo(id INT PRIMARY KEY AUTO_INCREMENT,NAME VARCHAR(128) NOT NULL,pnt POINT NOT NULL, ...
- [GO]使用select实现斐波那契
package main import "fmt" func fibonacci(ch chan <- int, quit <- chan bool) { x, y : ...