前言:昨天写NOIp2017队列,写+调辗转了3h+,不知道怎么的,就点进了一个神仙的链接,便在今日学习了神仙的fhq_treap。

简介:fhq_treap功能强大,支持splay支持的所有操作,代码简单,仅有两个核心函数\(merge\)和\(split\),更重要的是,它作为无旋的平衡树,是支持可持久化的。

正题:fhq_treap的实现

(0)树的域

对树的每个节点,我们维护

\(ch[2],siz,dat,val\)

分别为左右儿子,子树大小,BST性质的关键字,堆性质的关键字

其中堆是小根堆

(1)split函数

\(void \ split(now,k,\&x,\&y)\)

按照\(k\)值的意义可以有两种方式理解,其一为把以\(now\)为根的子树按照\(BST\)性质的权值按不大于\(k\)和大于\(k\)两种分裂成两颗子树,两颗子树的根分别为\(x\)和\(y\)。

这个函数是递归执行的,有严格的子问题划分性。

我们可以这样描述一次对整棵树的操作:

比较当前根节点权值\(dat[now]\)与\(k\)值

若大于,则根节点和右子树被划分为\(y\)树,当前根为\(now\),\(y\)树的左子树不确定,进入左子树求解子问题

若不大于,则根节点和左子树被划分为\(x\)树,当前根为\(now\),\(x\)树的右子树不确定,进入右子树求解子问题

复杂度分析:进入节点所构成的路径相当于对平衡树做了一次查询值为\(k\)的点的操作,复杂度与树的深度相关,根据\(treap\)的随机性,可以认为是\(O(logn)\)

代码实现:

void split(int now,int k,int &x,int &y)//把小于等于k的树分在x上
{
if(!now) {x=y=0;return;}
if(dat[now]>k) y=now,split(ls,k,x,ls);
else x=now,split(rs,k,rs,y);
updata(now);
}

其中,\(ls\),\(rs\)为宏定义的左右儿子,\(updata\)为更新节点的大小\(siz\)

另一种\(k\)值的意义为树中排名为\(k\)的节点,实现起来差不多

(2)merge函数

\(int \ merge(int \ x,int \ y)\)

意义为:把以\(x\)为根的子树和以\(y\)值为根的子树合并,返回新根节点。

注意这里有要求:以\(x\)值为根的子树的BST性质的最大节点小于以\(y\)为根的子树的最小节点。也就是说,这两棵子树本来就是在BST是一颗完全小于另外一颗,我们只需要在合并时保证堆性质即可。

这个函数是仍然递归执行的,有严格的子问题划分性。

我们可以这样描述一次对整棵树的操作:

比较两个根节点的\(val\)

若\(val[x]<val[y]\),好的当前根就是\(x\)了,\(x\)的左子树不用管了,我们进入\(x\)的右子树和\(y\)继续玩

否则,差不多啊反过来就行了

复杂度分析:两颗子树你一下我一下的走到了底,复杂度与子树的深度之和相关,可以认为是\(O(logn)\)

代码实现:

int Merge(int x,int y)//左树的权值小于右树
{
if(!x||!y) return x+y;
if(val[x]<val[y])
{
ch[x][1]=Merge(ch[x][1],y);
updata(x);
return x;
}
else
{
ch[y][0]=Merge(x,ch[y][0]);
updata(y);
return y;
}
}

(3)其他常见操作

有了功能强大的\(split\)和\(merge\),我们就可以很轻松的执行其他操作了

\(insert(k)\)

实现:把树按\(k\)分裂成两个,新建一个点再合并回去

代码:

void Insert(int k)
{
int x,y;
split(root,k,x,y);
root=Merge(Merge(x,New(k)),y);
}

\(extrack(k)\)//删除

实现:把树先分裂成两个,再把含\(k\)的那一颗把\(k\)单独分出来。注意如果有重复元素,单独的\(k\)构成的子树只删除根节点就够了。最后合并回去。

代码:

void extrack(int k)
{
int x,y,z;
split(root,k,x,y);
split(x,k-1,x,z);
z=Merge(ch[z][0],ch[z][1]);
root=Merge(x,Merge(z,y));
}

(4) 实例 洛谷P3369普通平衡树

Code:

#include <cstdio>
#include <cstdlib>
#define ls ch[now][0]
#define rs ch[now][1]
const int N=100010;
int siz[N],ch[N][2],dat[N],val[N],tot,root;
void updata(int now)
{
siz[now]=siz[ls]+siz[rs]+1;
}
void split(int now,int k,int &x,int &y)//把小于等于k的树分在x上
{
if(!now) {x=y=0;return;}
if(dat[now]>k) y=now,split(ls,k,x,ls);
else x=now,split(rs,k,rs,y);
updata(now);
}
int Merge(int x,int y)//左树的权值小于右树
{
if(!x||!y) return x+y;
if(val[x]<val[y])
{
ch[x][1]=Merge(ch[x][1],y);
updata(x);
return x;
}
else
{
ch[y][0]=Merge(x,ch[y][0]);
updata(y);
return y;
}
}
int New(int k)
{
siz[++tot]=1;dat[tot]=k;val[tot]=rand();
return tot;
}
void Insert(int k)
{
int x,y;
split(root,k,x,y);
root=Merge(Merge(x,New(k)),y);
}
void extrack(int k)
{
int x,y,z;
split(root,k,x,y);
split(x,k-1,x,z);
z=Merge(ch[z][0],ch[z][1]);
root=Merge(x,Merge(z,y));
}
void Rank(int k)
{
int x,y;
split(root,k-1,x,y);
printf("%d\n",siz[x]+1);
root=Merge(x,y);
}
void frank(int now,int x)
{
while(233)
{
if(siz[ls]>=x) now=ls;
else if(siz[ls]+1<x) x-=siz[ls]+1,now=rs;
else {printf("%d\n",dat[now]);return;}
}
}
void pre(int k)
{
int x,y;
split(root,k-1,x,y);
frank(x,siz[x]);
root=Merge(x,y);
}
void suc(int k)
{
int x,y;
split(root,k,x,y);
frank(y,1);
root=Merge(x,y);
}
int main()
{
int t,opt,x;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&opt,&x);
if(opt==1) Insert(x);
else if(opt==2) extrack(x);
else if(opt==3) Rank(x);
else if(opt==4) frank(root,x);
else if(opt==5) pre(x);
else suc(x);
}
return 0;
}

2018.7.28

fhq_treap 学习笔记的更多相关文章

  1. [总结] fhq_Treap 学习笔记

    无旋版 $Treap$. 只需要两个操作即可达到 $splay$ 的所有功能 1.$split$ 它的主要思想就是把一个 $Treap$ 分成两个. $split$ 操作有两种类型,一种是按照权值分配 ...

  2. Treap与fhq_Treap学习笔记

    1.普通Treap 通过左右旋来维护堆的性质 左右旋是不改变中序遍历的 #include<algorithm> #include<iostream> #include<c ...

  3. js学习笔记:webpack基础入门(一)

    之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...

  4. PHP-自定义模板-学习笔记

    1.  开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2.  整体架构图 ...

  5. PHP-会员登录与注册例子解析-学习笔记

    1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...

  6. 2014年暑假c#学习笔记目录

    2014年暑假c#学习笔记 一.C#编程基础 1. c#编程基础之枚举 2. c#编程基础之函数可变参数 3. c#编程基础之字符串基础 4. c#编程基础之字符串函数 5.c#编程基础之ref.ou ...

  7. JAVA GUI编程学习笔记目录

    2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...

  8. seaJs学习笔记2 – seaJs组建库的使用

    原文地址:seaJs学习笔记2 – seaJs组建库的使用 我觉得学习新东西并不是会使用它就够了的,会使用仅仅代表你看懂了,理解了,二不代表你深入了,彻悟了它的精髓. 所以不断的学习将是源源不断. 最 ...

  9. CSS学习笔记

    CSS学习笔记 2016年12月15日整理 CSS基础 Chapter1 在console输入escape("宋体") ENTER 就会出现unicode编码 显示"%u ...

随机推荐

  1. 腾讯云API弹性公网IP踩坑

    由于自己管理的云服务器数量比较多,时不时需要更换IP,在管理台上一下下点击,实在浪费时间,于是就想到了通过API调用的方式,将更换IP一系列动作,全部集成到Python代码里面,实现一行命令,完成IP ...

  2. Siki_Unity_1-2_Unity5.2入门课程_进入Unity开发的奇幻世界_Roll A Ball

    1-2 Unity5.2入门课程 进入Unity开发的奇幻世界 任务1:Roll A Ball项目简介 Unity官网的tutorial入门项目 方向键控制小球在平台上滚动,碰撞方块得分,消掉所有方块 ...

  3. 【springmvc+mybatis项目实战】杰信商贸-5.生产厂家DAO+SERVICE+CONTROLLER+JSP+配置文件

    上一篇我们创建了工程和一个Factory的po对象(javaBean),我们也写好了Mapper的映射文件,接下来我们来完成生产厂家的DAO与SERVICE,以及CONTROLLER,还有做显示的JS ...

  4. 【转】Buff机制及其实际运用

    转自 http://bbs.gameres.com/forum.php?mod=viewthread&tid=215027 首先我想说的是,这是一套机制,并不是单独的一个系统,所谓机制就是一种 ...

  5. python 打包

    一.下载 pip install Pyinstaller 二.使用Pyinstaller 1.使用下载安装的方式安装的Pyinstaller打包方式 将需要打包的文件放在解压得到的Pyinstalle ...

  6. HTML/JSP中一些单书名号标签的用途<%-- --%><!-- --><%@ %><%! %><% %><%= %>

    注释 <%-- --%>是(JSP)隐式注释,不会在页面显示的注释 <!-- -->是(Html)显示注释,会在JSP页面显示 关于注释还有单行隐式注释//和多行隐式注释/* ...

  7. POJ 3028 Shoot-out(概率DP)

    Description This is back in the Wild West where everybody is fighting everybody. In particular, ther ...

  8. Special Offer! Super Price 999 Bourles!

    Description Polycarpus is an amateur businessman. Recently he was surprised to find out that the mar ...

  9. Mininet实验 MAC地址学习

    实验目的 了解交换机的MAC地址学习过程. 了解交换机对已知单播.未知单播和广播帧的转发方式. 实验原理 MAC(media access control,介质访问控制)地址是识别LAN节点的标识.M ...

  10. iOS- iOS 和 Android 的后台推送原理各是什么?有什么区别?

    iOS 的推送iOS 在系统级别有一个推送服务程序使用 5223 端口.使用这个端口的协议源于 Jabber 后来发展为 XMPP ,被用于 Gtalk 等 IM 软件中.所以, iOS 的推送,可以 ...