首先说一下,

这个东西可以搞一切bst,treap,splay所能搞的东西

pre

今天心血来潮,

想搞一搞平衡树,

先百度了一下平衡树,发现正宗的平衡树写法应该是在二叉查找树的基础上加什么左左左右右左右右的旋转之类的,

思路比较好理解,但是

代码量。。。。。。。。

一看就头大,,

然后,在洛谷翻题解的时候无意间看到了远航之曲发的一篇非常短小精悍的题解,

于是就学了一下

FHQ Treap

这个东西的学名应该是叫做fhq treap,应该是treap的强化版。

整个数据结构中只有两个操作:

1.分离(split) 就是把一棵树分成两个树

2.合并(merge)把两棵树合成一棵树

对于FHQ 的两种操作的原理以及实现,

我在这里就不去赘述,

大家可以去看一下远航之曲写的博客

http://www.yhzq-blog.cc/fhq-treap%e6%80%bb%e7%bb%93/

在这里我主要是在讲解一下代码的具体实现(当然也有可能不对。。)

CODE

题目链接:

https://www.luogu.org/problem/show?pid=3369

先说一下各个数组的含义:

 int ch[MAXN][];// 0左孩子 1右孩子
int val[MAXN];// 每一个点的权值
int pri[MAXN];// 随机生成的附件权值
int siz[MAXN];// 以i为节点的树的节点数量
int sz;// 总结点的数量

然后来分别说明一下六中操作的实现

1.插入:

split(root,a,x,y);
root=merge(merge(x,new_node(a)),y);

这个比较好理解,我们先把树分为x,y两部分,然后把新的节点a看做是一棵树,先与x合并,合并完之后将合并的整体与y合并

2.删除

 split(root,a,x,z);
split(x,a-,x,y);
y=merge(ch[y][],ch[y][]);
root=merge(merge(x,y),z);

首先我们把树分为x和z两部分

那么x树中的最大权值为a

再把x分为x和y两部分。

此时x中的最大权值为a-1,且权值为a的节点一定是y的根节点。

然后我们可以无视y的根节点,直接把y的左右孩子合并起来,这样就成功的删除了根节点,

最后再把x,y,z合并起来就好

3.查询a的排名

 split(root,a-,x,y);
printf("%d\n",siz[x]+);
root=merge(x,y);

我们首先按照a-1的权值把树分开。

那么x树中最大的应该是a-1。

那么a的排名就是siz[x]+1

4.查询排名为a的数

printf("%d\n",val[kth(root,a)]);

直接调用查找排名的函数即可,

这个函数应该比较好理解。。

5.求x的前驱(前驱定义为小于a,且最大的数)

 split(root,a-,x,y);
printf("%d\n",val[kth(x,siz[x])]);
root=merge(x,y);

因为要小于a,那么我们按照a-1的权值划分,

x中最大的一定是<=a-1的,

所以我们直接输出x中最大的数就好,

(这里有一个小技巧,因为siz储存的是节点的数目,然后根据二叉查找树的性质,编号最大的就是值最大的)

6.求x的后继(后继定义为大于x,且最小的数)

 split(root,a,x,y);
printf("%d\n",val[kth(y,)]);
root=merge(x,y);

和上面的原理类似,

留给大家思考,

不懂的再问我。

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<ctime>
using namespace std;
const int MAXN=;
static void read(int &n)
{
char c='+';int x=;bool flag=;
while(c<''||c>''){c=getchar();if(c=='-')flag=;}
while(c>=''&&c<=''){x=(x<<)+(x<<)+(c-);c=getchar();}
flag==?n=-x:n=x;
}
int ch[MAXN][];// 0左孩子 1右孩子
int val[MAXN];// 每一个点的权值
int pri[MAXN];// 随机生成的附件权值
int siz[MAXN];// 以i为节点的树的节点数量
int sz;// 总结点的数量
void update(int x)
{
siz[x]=+siz[ch[x][]]+siz[ch[x][]];
}
int new_node(int v)
{
siz[++sz]=;// 新开辟一个节点
val[sz]=v;
pri[sz]=rand();
return sz;
}
int merge(int x,int y)// 合并
{
if(!x||!y) return x+y;// x和y中必定有一个是0
if(pri[x]<pri[y])// 把x加到左边的树上
{
ch[x][]=merge(ch[x][],y);// 不懂的看GIF图
update(x);
return x;
}
else
{
ch[y][]=merge(x,ch[y][]);
update(y);
return y;
}
}
void split(int now,int k,int &x,int &y)
{
if(!now) x=y=;// 到达叶子节点
else
{
if(val[now]<=k)// 分离右子树
x=now,split(ch[now][],k,ch[now][],y);
else
y=now,split(ch[now][],k,x,ch[now][]);
update(now);
}
}
int kth(int now,int k)// 查询排名
{
while()
{
if(k<=siz[ch[now][]])
now=ch[now][];// 在左子树中,且数量小于左子树的大小,迭代寻找
else if(k==siz[ch[now][]]+)
return now;// 找到了
else
k-=siz[ch[now][]]+,now=ch[now][];// 去右子树找
}
}
int main()
{
srand((unsigned)time(NULL));
int n;
read(n);
int root=,x,y,z;
for(int i=;i<=n;i++)
{
int how,a;
read(how);read(a);
if(how==)// 插入
{
split(root,a,x,y);
root=merge(merge(x,new_node(a)),y);
}
else if(how==)//删除x
{
split(root,a,x,z);
split(x,a-,x,y);
y=merge(ch[y][],ch[y][]);
root=merge(merge(x,y),z);
}
else if(how==)//查询x的排名
{
split(root,a-,x,y);
printf("%d\n",siz[x]+);
root=merge(x,y);
}
else if(how==)// 查询排名为x的数
{
printf("%d\n",val[kth(root,a)]);
}
else if(how==)// 求x的前驱
{
split(root,a-,x,y);
printf("%d\n",val[kth(x,siz[x])]);
root=merge(x,y);
}
else if(how==)// 求x的后继
{
split(root,a,x,y);
printf("%d\n",val[kth(y,)]);
root=merge(x,y);
}
}
return ;
}

最后说一下,FHQ其实是可以处理区间问题的,

主要就是先把r+1的拆出来,然后把l的拆出来。

但是有些细节问题特别神奇,至今没有搞懂。

如果你会的话希望你能给本蒟蒻讲一下。

谢谢

FHQ Treap小结(神级数据结构!)的更多相关文章

  1. 【数据结构】FHQ Treap详解

    FHQ Treap是什么? FHQ Treap,又名无旋Treap,是一种不需要旋转的平衡树,是范浩强基于Treap发明的.FHQ Treap具有代码短,易理解,速度快的优点.(当然跟红黑树比一下就是 ...

  2. fhq treap——简单又好写的数据结构

    今天上午学了一下fhq treap感觉真的很好用啊qwq 变量名解释: \(size[i]\)表示以该节点为根的子树大小 \(fix[i]\)表示随机权值 \(val[i]\)表示该节点的值 \(ch ...

  3. 【数据结构】平衡树splay和fhq—treap

    1.BST二叉搜索树 顾名思义,它是一棵二叉树. 它满足一个性质:每一个节点的权值大于它的左儿子,小于它的右儿子. 当然不只上面那两种树的结构. 那么根据性质,可以得到该节点左子树里的所有值都比它小, ...

  4. 在平衡树的海洋中畅游(四)——FHQ Treap

    Preface 关于那些比较基础的平衡树我想我之前已经介绍的已经挺多了. 但是像Treap,Splay这样的旋转平衡树码亮太大,而像替罪羊树这样的重量平衡树却没有什么实际意义. 然而类似于SBT,AV ...

  5. 并不对劲的fhq treap

    听说很对劲的太刀流不止会splay一种平衡树,并不对劲的片手流为了反驳他,并与之针锋相对,决定学学高端操作. 很对劲的太刀流-> 据说splay常数极大,但是由于只知道splay一种平衡树能对序 ...

  6. fhq treap最终模板

    新学习了fhq treap,厉害了 先贴个神犇的版, from memphis /* Treap[Merge,Split] by Memphis */ #include<cstdio> # ...

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

  8. 【fhq Treap】bzoj1500(听说此题多码上几遍就能不惧任何平衡树题)

    1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 15112  Solved: 4996[Submit][Statu ...

  9. 可持久化treap(FHQ treap)

    FHQ treap 的整理 treap = tree + heap,即同时满足二叉搜索树和堆的性质. 为了使树尽可能的保证两边的大小平衡,所以有一个key值,使他满足堆得性质,来维护树的平衡,key值 ...

随机推荐

  1. 75道经典AI面试题,我就想把你们安排的明明白白的!(含答案)

    基础知识(开胃菜) Python 1.类继承 有如下的一段代码: class A(object): def show(self): print 'base show' class B(A): def ...

  2. javascript事件循环

    js单线程 js是单线程的,这样更有利与用户交互以及DOM操作;有关进程与线程的详细解释可以点击传送门:尽管webworker可以实现多线程,但本质上他还属于单线程,由webworker创建的线程都由 ...

  3. 深圳scala-meetup-20180902(3)- Using heterogeneous Monads in for-comprehension with Monad Transformer

    scala中的Option类型是个很好用的数据结构,用None来替代java的null可以大大降低代码的复杂性,它还是一个更容易解释的状态表达形式,比如在读取数据时我们用Some(Row)来代表读取的 ...

  4. 处理ios的overflow滚动bug

    先说说这个bug的场景 .container{ height:100vh; overflow-y:scroll; } 没毛病,总有这种类似的情况,需要在容器内滚动,但是!这种容器内的滚动在ios上面处 ...

  5. 生成多个git ssh密钥

    如果你已经有了一套名为 id_rsa 的公秘钥,将要生成另外一个公钥,比如 aysee ,你也可以使用任何你喜欢的名字. 步骤如下: 1.生成一个新的自定义名称的公钥: ssh-keygen -t r ...

  6. 机器学习技法笔记:04 Soft-Margin Support Vector Machine

    Roadmap Motivation and Primal Problem Dual Problem Messages behind Soft-Margin SVM Model Selection S ...

  7. 一站式SpringBoot for NoSQL Study Tutorial 开发教程学习手册

    SpringBoot2.0 + NoSQL使用教程,项目名称:“SpringBoot2NoSQL” 项目地址: https://gitee.com/475660/SpringBoot2NoSQL 项目 ...

  8. Liferay7 BPM门户开发之19: 理解Service Builder体系

    Service Builder是Liferay为业务开发而设计的模型驱动(model-driven)平台工具,提供一系列的实体类.数据持久化.服务相关的代码自动生成服务.支持Hibernate and ...

  9. laravel5实现第三方登录(微信)

    背景 最近手头一个项目需要实现用户在网站的第三方登录(微信和微博),后端框架laravel5.4. 实现过程以微信网页版第三方登录,其他于此类似,在此不做重复. 准备工作 网站应用微信登录是基于OAu ...

  10. 使用Chrome开发者工具调试Android端内网页(微信,QQ,UC,App内嵌页等)

    使用Chrome开发者工具调试Android端内网页(微信,QQ,UC,App内嵌页等) 前言 移动端页面调试一直是好多朋友头疼的问题,iOS 由于其封闭的特性和整体较高的性能,整体适配相对好做,调试 ...