今天上午学了一下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——简单又好写的数据结构的更多相关文章

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

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

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

  3. FHQ Treap小结(神级数据结构!)

    首先说一下, 这个东西可以搞一切bst,treap,splay所能搞的东西 pre 今天心血来潮, 想搞一搞平衡树, 先百度了一下平衡树,发现正宗的平衡树写法应该是在二叉查找树的基础上加什么左左左右右 ...

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

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

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

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

  6. BZOJ3159: 决战(FHQ Treap)

    传送门: 解题思路: 算是补坑了,这题除了Invert以外就可以树剖线段树解决了. 考虑Invert操作,延续先前树链剖分的做法,考虑先前算法的瓶颈. 最暴力的方法是暴力交换权值,然而这种方法忽略了当 ...

  7. 可持久化treap(FHQ treap)

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

  8. 并不对劲的fhq treap

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

  9. FHQ treap学习(复习)笔记

    .....好吧....最后一篇学习笔记的flag它倒了..... 好吧,这篇笔记也鸽了好久好久了... 比赛前刷模板,才想着还是补个坑吧... FHQ,这个神仙(范浩强大佬),发明了这个神仙的数据结构 ...

随机推荐

  1. Java实现主线程等待子线程

    本文介绍两种主线程等待子线程的实现方式,以5个子线程来说明: 1.使用Thread的join()方法,join()方法会阻塞主线程继续向下执行. 2.使用Java.util.concurrent中的C ...

  2. MongoDB数据仓储

    本篇是作为另一篇随笔的一部分‘搭建一个Web API项目’ MogonDB官网:https://www.mongodb.org/ 安装过程参考园友的分享http://www.cnblogs.com/l ...

  3. Android中的网络编程

    谷歌在Android6.0之后就废弃了使用HttpClinet进行网络连接.所以,这里需要重点学习的是通过HttpUrlConnect进行网络连接. String path="这里是你想要的 ...

  4. Cassandra读写性能测试

    1. 测试目的 测试Cassandra集群读写TPS的极值,确定Cassandra读写性能. 2. 测试环境 2.1 硬件信息 CPU 8核 Intel(R) Xeon(R) CPU E5-2650 ...

  5. git的突出解决--git rebase之abort、continue、skip

    (1)应用实例描述 假设在github或者gitoschina上建立了一个项目,默认分支为master分支,远程master分支上c.sh文件内容: 开发者A.B分别将项目拷贝到自己本地进行开发 某一 ...

  6. 【LA 3989 训练指南】女士的选择 【稳定婚姻问题】

    我们先来学一下稳定婚姻问题 什么是稳定婚姻问题? 有n个女士和n个男士,他们要一一进行配对.每个男士心中对这n个女士都有一个排名,同理,每个女士心里对n个男性也有一个排名.我们要做的是,在他们配对完成 ...

  7. socket,TCP/IP的理解(转)

    TCP/IP 要想理解socket首先得熟悉一下TCP/IP协议族, TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间 ...

  8. Nlog- Application Logging in C#

    当你在谷歌搜索 Application  Loggin in C#,排在最前面的是这个 .NET Logging Tools and Libraries ,点击进去你会发现里面收录了不错的日记工具及文 ...

  9. ceph常用指令

    一.集群 1.启动一个ceph 进程 启动mon进程 service ceph start  mon.node1 启动msd进程 service ceph start mds.node1 启动osd进 ...

  10. bootstrap-海棠

    12 缩略图和警告框 <p class='alert alert-info'>这个是警告组<button class='close' data-dismiss='alert'> ...