今天上午学了一下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. android学习-Eclipse中修改Android项目图标

    参考原文:http://blog.csdn.net/wpwbb510582246/article/details/52556753 方法一:替换res文件夹下的ic_launcher-web.png图 ...

  2. 搭建Git Server - Centos+Gitosis

    参考并部分转载自:http://www.pfeng.org/archives/757 1. 安装依赖 yum -y install curl-devel expat-devel gettext-dev ...

  3. 使用ControllerClassNameHandlerMapping实现SpringMVC的CoC配置

    使用CoC,惯例优先原则(convention over configuration)的方式来配置SpringMVC可以帮我们声明Controller的时候省下很多功夫. 只要我们的Controlle ...

  4. MYSQL的随机查询的实现方法

    的确是那么回事. MYSQL的随机抽取实现方法.举个例子,要从tablename表中随机提取一条记录,大家一般的写法就是:SELECT * FROM tablename ORDER BY RAND() ...

  5. beego 中文教程

    https://www.kancloud.cn/hello123/beego/126087

  6. Codeforces 667C DP

    题意:给你一个字符串,这个字符串的构造方法如下:先选择一个长度大于4的前缀,然后每次向字符串尾部添加一个长度为2或者长度为3的后缀,不能添加连续的相同的后缀,问可能的后缀有哪些?并按字典序输出去. 思 ...

  7. PHP微信授权登录信息

    文件1:index.php //换成自己的接口信息 $appid = 'XXXXX'; header('location:https://open.weixin.qq.com/connect/oaut ...

  8. 801. Minimum Swaps To Make Sequences Increasing 为使两个数组严格递增,所需要的最小交换次数

    [抄题]: We have two integer sequences A and B of the same non-zero length. We are allowed to swap elem ...

  9. tornado异步请求非阻塞-乾颐堂

    前言 也许有同学很迷惑:tornado不是标榜异步非阻塞解决10K问题的嘛?但是我却发现不是torando不好,而是你用错了.比如最近发现一个事情:某网站打开页面很慢,服务器cpu/内存都正常.网络状 ...

  10. 爬虫 之 scrapy-redis组件

    scrapy-redis组件 scrapy-redis是一个基于redis的scrapy组件,通过它可以快速实现简单分布式爬虫程序,该组件本质上提供了三大功能: scheduler - 调度器 dup ...