今天上午学了一下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. go_内建变量类型

    bool, string (u)int, (u)int8, (u)int16, (u)int32, (u)int64, uintptr (uintptr 是指针) byte, rune(表示字符cha ...

  2. 高性能Web服务器Nginx的配置与部署研究(10)核心模块之HTTP模块Location相关指令

    一.基本语法 语法:location [= | ~ | ~* | ^~] </uri/> {...} 缺省:N/A 作用域:server 二.匹配规则 1. 四种匹配方式 = 精确匹配 ~ ...

  3. XIb中使用tableview报错UIViewAlertForUnsatisfiableConstraints

    1.使用断点工具并不能找出错误,最后仔细看了下报错信息 2.报错信息 [LayoutConstraints] Unable to simultaneously satisfy constraints. ...

  4. ROS tf 编程指南

    ROS (Robot Operating System, 机器人操作系统)是最知名的机器人操作系统,广泛应用于无人驾驶和机器人,tf(transforms,坐标系转换)是ROS下的一个常用的工具库.r ...

  5. EZOJ #227

    传送门 分析 我们发现第一段数和最后一段数对答案的贡献系数为1/-1,其余为0/2/-2 而且对于相邻两段不能系数均非0 于是可以dp 代码 #include<iostream> #inc ...

  6. Python 中的 is 和 id-乾颐堂

    (ob1 is ob2) 等价于 (id(ob1) == id(ob2)) 首先id函数可以获得对象的内存地址,如果两个对象的内存地址是一样的,那么这两个对象肯定是一个对象.和is是等价的.Pytho ...

  7. PBOC中文件结构,文件类型解析

    1.明确两个规范,a. ISO7816   b.EMV规范/PBOC规范,二者的区别,7816是ISO制定的,是国际规范,而EMV规范是卡组织制定的,是遵循ISO7816规范的,PBOC是抄袭EMV规 ...

  8. 【转】C++中#if #ifdef 的作用

    一般情况下,源程序中所有的行都参加编译.但是有时希望对其中一部分内容只在满足一定条件才进行编译,也就是对一部分内容指定编译的条件,这就是“条件 编译”.有时,希望当满足某条件时对一组语句进行编译,而当 ...

  9. Memcached在Windows下的配置和使用(转)

    出处:http://www.cnblogs.com/sunniest/p/4154209.html Memcached学习笔记---- 安装和配置 首先,下载Memcached相关文件. 打开控制台, ...

  10. NodeJS下的阿里云企业邮箱邮件发送问题

    还没有到11点,再顺带发一个上次碰到NodeJS的邮箱插件nodeMailer不支持阿里云邮件问题. 网上很多资料都默认使用QQ之类的邮箱,因为nodeMailer默认添加了QQ之类的SMTP地址,但 ...