范浩强treap——可持久化
当平衡树需要可持久化的时候,意味着我们需要访问以前的某个时间点的平衡树,就要保持以前的树形态不变,新建一个时间戳,构建一棵新的树。
如果用以前的旋转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——可持久化的更多相关文章
- 范浩强treap 普通平衡树
增加Split(分裂),Merge(合并)操作,非常好写,时间也不比普通treap慢什么. #include<bits/stdc++.h> using namespace std; str ...
- 旷视6号员工范浩强:高二开始实习,“兼职”读姚班,25岁在CVPR斩获第四个世界第一...
初来乍到,这个人说话容易让人觉得"狂". "我们将比赛结果提交上去,果不其然,是第一名的成绩."当他说出这句话的时候,表情没有一丝波澜,仿佛一切顺理成章. 他说 ...
- 挂羊头卖狗肉蓄意欺骗读者——谭浩强《C程序设计(第四版)》中所谓的“按照C99”(二)
挂羊头卖狗肉蓄意欺骗读者——谭浩强<C程序设计(第四版)>中所谓的“按照C99”(二) 在<谭C>p4:“本书的叙述以C99标准为依据”,下面从C89到C99的主要变化方面来看 ...
- C语言学习笔记---谭浩强
前段时间有机会去面试了一次,真是备受“打击”(其实是启发),总的来说就是让我意识到了学习工具和学习技术的区别.所以最近在看一些数据结构和算法,操作系统,python中的并行编程与异步编程等东西.然而数 ...
- C指针笔试题,蛋疼的多重指针运算,谭浩强的阴影
对指针的概念清晰的话,做这种题只要耐心就行,然而看这种题就烦(被同学吐槽为谭浩强的阴影……草泥马这种C风格题有意义吗?出题人脑子被门夹了?而且C++11都不支持字面值字符串直接转换成char*了.好吧 ...
- c++面向对象程序设计 课后题 答案 谭浩强 第四章
c++面向对象程序设计课后题答案 谭浩强 第四章 1: #include <iostream> using namespace std; class Complex {public: Co ...
- c++面向对象程序设计 谭浩强 第三章答案
2: #include <iostream> using namespace std; class Date {public: Date(int,int,int); Date(int,in ...
- c++面向对象程序设计 谭浩强 第二章答案
类体内定义成员函数 #include <iostream> using namespace std; class Time { public: void set_time(); void ...
- c++面向对象程序设计 谭浩强 第一章答案
c++面向对象程序设计 谭浩强 答案 第一章 目录: c++面向对象程序设计 谭浩强 答案 第一章 c++面向对象程序设计 谭浩强 答案 第二章 c++面向对象程序设计 谭浩强 答案 第三章 c++面 ...
随机推荐
- onblur & onchange
本文地址:http://www.cnblogs.com/veinyin/p/7606914.html 两者均可用于验证是否输入数据 onblur : 表示不再是焦点,是 onfocus 的相反事件, ...
- layer弹窗的跳转功能
1,本弹窗直接跳转父页面: @if(session('message')) <script> window.parent.location.reload(); //刷新父页面 var in ...
- Shodan 使用
本文来自:Shodan新手入坑指南, 记录简要用法,以便使用. 文章先给出搜索过滤方法,然后再简单介绍两种使用shodan的方法:使用命令和编写代码. 搜索过滤 hostname:搜索指定的主机或域名 ...
- JWT 拓展
JWT适用场景 https://www.jianshu.com/p/af8360b83a9f 适用于一次性操作的认证,颁布一个很短过期时间的JWT给浏览器. 无状态的JWT无法实现精确的在线人数统计. ...
- python并发编程之threading线程(一)
进程是系统进行资源分配最小单元,线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.进程在执行过程中拥有独立的内存单元,而多个线程共享内存等资源. 系列文章 py ...
- html的loadrunner脚本2
Action(){ char buf[1911]; //¶¨Òå×Ö·ûÊý×飬Ö÷ÒªÓÃÓÚдÈëXML±¨Îĵ½»º³åÇø char str_Body[4086]; //³Ð½Ó±¨Î ...
- Android仿新浪新闻SlidingMenu界面的实现 .
先看看原图: 如图所示,这种侧滑效果以另一种方式替代了原先tab导航的那种用户体验方式 给人耳目一新的感觉,现已被广大知名应用所效仿,如新浪新闻,网易新闻,人人网等 那么这种效果该如何实现呢?那就需要 ...
- DBCP object created 日期 by the following code was never closed:
1.分析 看到标题 DBCP 首先想到的肯定是 数据库连接池哪方面有问题,那么先别着急去解决,不要一股脑就钻进逻辑代码中,然后启用调试就开始一步一步 的分析.我们首先要做的就是想,想想数据库连接池,在 ...
- HDU 1217 Arbitrage(Bellman-Ford判断负环+Floyd)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1217 题目大意:问你是否可以通过转换货币从中获利 如下面这组样例: USDollar 0.5 Brit ...
- open()函数文件操作
open函数,该函数用于文件处理 操作文件时,一般需要经历如下步骤: (1)打开文件 (2)操作文件 一.打开文件 文件句柄 = open("文件路径","模式& ...