当平衡树需要可持久化的时候,意味着我们需要访问以前的某个时间点的平衡树,就要保持以前的树形态不变,新建一个时间戳,构建一棵新的树。

如果用以前的旋转treap可能就不方便做到(又要打时间戳,又要新建节点,又要旋转),而且涉及到旋转,空间可能会承受不住,我们需要用到一种新的平衡树——fhq treap

这是一种非常好写的treap 核心操作有两个,一个是split一个是merge。

split(node,k,x,y) 意思是把以node为跟的子树分成两部分,一部分小于等于k(根为x),一部分大于k(根为y)。在可持久化的时候要保证以前的树的形态不变,就要每一次copy一个节点过来。

而我们每一次递归只会访问一个节点的左右子树中的一个节点,又因为treap的均摊深度为log,所以总体的空间为nlogn,是非常高效的。

说完split接下来是merge

merge函数,是有返回值的,merge(x,y) 是把以x为根的子树和以y为根的子树合并起来,返回这棵新的树的根,递归的实现,非常好懂。

接下来的所有操作都是基于以上两个核心的操作,非常好理解,比旋转的treap好理解而且更好写,注意可持久化即可。

——by VANE

 #include<bits/stdc++.h>
using namespace std;
const int N=;
struct node
{
int ch[];
int fix,key,sz;
}t[N*];
int root[N],cnt=;
int copynode(int x)
{
cnt++;
t[cnt]=t[x];
return cnt;
}
void update(int cur)
{
if(cur)
t[cur].sz=t[t[cur].ch[]].sz+t[t[cur].ch[]].sz+;
}
int newnode(int val)
{
cnt++;
t[cnt].ch[]=t[cnt].ch[]=;
t[cnt].key=val;
t[cnt].sz=;
t[cnt].fix=rand();
return cnt;
}
void split(int now,int k,int &x,int &y)
{
if(!now) x=y=;
else
{
if(t[now].key<=k)
{
x=copynode(now);
split(t[x].ch[],k,t[x].ch[],y);
}
else
{
y=copynode(now);
split(t[y].ch[],k,x,t[y].ch[]);
}
update(x);
update(y);
}
}
int merge(int x,int y)
{
if(!x||!y) return x+y;
if(t[x].fix<t[y].fix)
{
int r=copynode(x);
t[r].ch[]=merge(t[r].ch[],y);
update(r);
return r;
}
else
{
int r=copynode(y);
t[r].ch[]=merge(x,t[r].ch[]);
update(r);
return r;
}
}
void insert(int bb,int val)
{
int x,y,z;
x=y=z=;
split(root[bb],val,x,y);
z=newnode(val);
root[bb]=merge(merge(x,z),y);
}
void Delete(int bb,int val)
{
int x,y,z;
split(root[bb],val,x,z);
split(x,val-,x,y);
y=merge(t[y].ch[],t[y].ch[]);
root[bb]=merge(merge(x,y),z);
}
int getpos(int now,int k)
{
while()
{
if(k<=t[t[now].ch[]].sz) now=t[now].ch[];
else if(k==t[t[now].ch[]].sz+) return now;
else k-=t[t[now].ch[]].sz+,now=t[now].ch[];
}
}
int getkth(int bb,int val)
{
int x,y;
int ret;
split(root[bb],val-,x,y);
ret=t[x].sz+;
return ret;
}
int getval(int now,int k)
{
int x;
x=getpos(now,k);
return t[x].key;
}
int getpre(int bb,int val)
{
int x,y;
int k,ret;
split(root[bb],val-,x,y);
if(x) k=t[x].sz;
else return -;
ret=getval(x,k);
return ret;
}
int getnext(int bb,int val)
{
int x,y;
split(root[bb],val,x,y);
if(!y) return ;
int ret=getval(y,);
return ret;
}
int main()
{
int n,bb,cmd,val;
scanf("%d",&n);
for(int i=;i<=n;++i)
{
scanf("%d%d%d",&bb,&cmd,&val);
root[i]=root[bb];
switch(cmd)
{
case :insert(i,val);break;
case :Delete(i,val);break;
case :printf("%d\n",getkth(i,val));break;
case :printf("%d\n",getval(root[i],val));break;
case :printf("%d\n",getpre(i,val));break;
case :printf("%d\n",getnext(i,val));break;
}
}
}

范浩强treap——可持久化的更多相关文章

  1. 范浩强treap 普通平衡树

    增加Split(分裂),Merge(合并)操作,非常好写,时间也不比普通treap慢什么. #include<bits/stdc++.h> using namespace std; str ...

  2. 旷视6号员工范浩强:高二开始实习,“兼职”读姚班,25岁在CVPR斩获第四个世界第一...

    初来乍到,这个人说话容易让人觉得"狂". "我们将比赛结果提交上去,果不其然,是第一名的成绩."当他说出这句话的时候,表情没有一丝波澜,仿佛一切顺理成章. 他说 ...

  3. 挂羊头卖狗肉蓄意欺骗读者——谭浩强《C程序设计(第四版)》中所谓的“按照C99”(二)

    挂羊头卖狗肉蓄意欺骗读者——谭浩强<C程序设计(第四版)>中所谓的“按照C99”(二) 在<谭C>p4:“本书的叙述以C99标准为依据”,下面从C89到C99的主要变化方面来看 ...

  4. C语言学习笔记---谭浩强

    前段时间有机会去面试了一次,真是备受“打击”(其实是启发),总的来说就是让我意识到了学习工具和学习技术的区别.所以最近在看一些数据结构和算法,操作系统,python中的并行编程与异步编程等东西.然而数 ...

  5. C指针笔试题,蛋疼的多重指针运算,谭浩强的阴影

    对指针的概念清晰的话,做这种题只要耐心就行,然而看这种题就烦(被同学吐槽为谭浩强的阴影……草泥马这种C风格题有意义吗?出题人脑子被门夹了?而且C++11都不支持字面值字符串直接转换成char*了.好吧 ...

  6. c++面向对象程序设计 课后题 答案 谭浩强 第四章

    c++面向对象程序设计课后题答案 谭浩强 第四章 1: #include <iostream> using namespace std; class Complex {public: Co ...

  7. c++面向对象程序设计 谭浩强 第三章答案

    2: #include <iostream> using namespace std; class Date {public: Date(int,int,int); Date(int,in ...

  8. c++面向对象程序设计 谭浩强 第二章答案

    类体内定义成员函数 #include <iostream> using namespace std; class Time { public: void set_time(); void ...

  9. c++面向对象程序设计 谭浩强 第一章答案

    c++面向对象程序设计 谭浩强 答案 第一章 目录: c++面向对象程序设计 谭浩强 答案 第一章 c++面向对象程序设计 谭浩强 答案 第二章 c++面向对象程序设计 谭浩强 答案 第三章 c++面 ...

随机推荐

  1. 【LibreOJ】#6257. 「CodePlus 2017 12 月赛」可做题2

    [题意]数列满足an=an-1+an-2,n>=3.现在a1=i,a2=[l,r],要求满足ak%p=m的整数a2有多少个.10^18. [算法]数论(扩欧)+矩阵快速幂 [题解]定义fib(i ...

  2. 目标检测-基于Pytorch实现Yolov3(1)- 搭建模型

    原文地址:https://www.cnblogs.com/jacklu/p/9853599.html 本人前段时间在T厂做了目标检测的项目,对一些目标检测框架也有了一定理解.其中Yolov3速度非常快 ...

  3. Linux内核同步原语之原子操作【转】

    转自:http://blog.csdn.net/npy_lp/article/details/7262388 避免对同一数据的并发访问(通常由中断.对称多处理器.内核抢占等引起)称为同步. ——题记 ...

  4. Linux sqlite3基本命令

    简介sqlite3一款主要用于嵌入式的轻量级数据库,本文旨在为熟悉sqlite3基本命令提供技术文档. 备注:本文所有操作均在root用户下进行. 1.安装sqlite3 ubuntu下安装sqlit ...

  5. Codeforces Round #456 (Div. 2)

    Codeforces Round #456 (Div. 2) A. Tricky Alchemy 题目描述:要制作三种球:黄.绿.蓝,一个黄球需要两个黄色水晶,一个绿球需要一个黄色水晶和一个蓝色水晶, ...

  6. 「caffe编译bug」python/caffe/_caffe.cpp:10:31: fatal error: numpy/arrayobject.h: No such file or directory

    在Makefile.config找到PYTHON_INCLUDE,发现有点不同: PYTHON_INCLUDE := /usr/include/python2.7 \         /usr/lib ...

  7. javaScript如何跳出多重循环break、continue

    先来说说break和continue之间的区别 for(var i=0;i<10;i++){  if(i>5){  break;  }}console.log(i);  ---6  •当i ...

  8. Effective C++笔记(六):继承与面向对象设计

    参考:http://www.cnblogs.com/ronny/p/3756494.html 条款32:确定你的public继承塑模出is-a关系 “public继承”意味着is-a.适用于base ...

  9. [Spring Data JPA问题]Executing an update/delete query; nested exception is javax.persistence.TransactionRequiredException

    JPQL如下: @Modifying(clearAutomatically = true) @Query("UPDATE SyncTestFromTKDO SET stuAns = '' w ...

  10. Source Insight 4.0 文件类型、编码格式、tab转空格、tab键自动补全设置。。。

    1.编码格式  -- 在 Options->Preferences->Files 中的最下面,Default enconding 为 UTF-8 2.tab转空格 其他相关设置如下: 以下 ...