「FHQ Treap」学习笔记
话说天下大事,就像fhq treap —— 分久必合,合久必分
简单讲一讲。非旋treap主要依靠分裂和合并来实现操作。(递归,不维护fa不维护cnt)
合并的前提是两棵树的权值满足一边的最大的比另一边最小的还小。因此时合并时只需要维护键值的堆性质即可。这样每一次比较根节点,如果x比y小那么y直接接到x的右子树即可(需要满足权值的平衡树性质);否则的话只需要反过来,把x接到y的左子树上。merge函数返回的值应当是合并完后的根节点。
分裂分为两种,排名和权值。然而我认为它们本质上是一样的。对于权值的分裂,对于每一个子树的根节点,若根节点比给定值a小,那么此节点及左子树一定比a小,归入x。否则此节点及右子树归入y。然后再递归操作还没有分类的那一个子树就好了。代码实现中的引用用的非常巧妙。可以把这里的引用理解为是需要修改的东西,利用递归的过程对其作出修改。
合并看键值,分裂看权值。
$Merge$
int merge(int u, int v){
if(!u||!v) return u|v;
if(key[u] < key[v]){
ch[u][] = merge(ch[u][], v);
pushup(u);
return u;
}
else{
ch[v][] = merge(u, ch[v][]);
pushup(v);
return v;
}
}
$Split$
void split_a(int u, int a, int& x, int& y){
if(!u){ x = y = ; return; }
if(val[u] <= a){
x = u;
split_a(ch[u][], a, ch[u][], y);
}
else{
y = u;
split_a(ch[u][], a, x, ch[u][]);
}
pushup(u);
}
void split_k(int u, int k, int& x, int& y){
if(!u){ x = y = ; return; }
if(size[ch[u][]]+1 <= k){
x = u;
split_k(ch[u][], k-size[ch[u][]]-1, ch[u][], y);
}
else{
y = u;
split_k(ch[u][], k, x, ch[u][]);
}
pushup(u);
}
有了这两个操作,其他操作yy一下即可,非常简便。
当然,在查询k大排名或前驱后继时,完全可以用普通平衡树(如splay)的做法。因为它满足平衡树的性质。也就是傻乎乎的去logn的从根节点往下走。那么既然我们有了split,查询最大最小值应该很方便了。要尽量让代码精简啊!
My Code:
/*By DennyQi 2018*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#include <ctime>
#include <cstdlib>
using namespace std;
typedef long long ll;
const int MAXN = ;
const int INF = 0x3f3f3f3f;
inline int Max(const int a, const int b){ return (a > b) ? a : b; }
inline int Min(const int a, const int b){ return (a < b) ? a : b; }
inline int read(){
int x = ; int w = ; register char c = getchar();
for(; c ^ '-' && (c < '' || c > ''); c = getchar());
if(c == '-') w = -, c = getchar();
for(; c >= '' && c <= ''; c = getchar()) x = (x<<) + (x<<) + c - ''; return x * w;
}
int N,opt,x,num_node,RooT;
int ch[MAXN][],val[MAXN],key[MAXN],size[MAXN];
inline void pushup(int x){
size[x] = size[ch[x][]] + size[ch[x][]] + ;
}
inline void clear(int x){
size[x]=val[x]=key[x]=ch[x][]=ch[x][]=;
}
int merge(int u, int v){
if(!u||!v) return u|v;
if(key[u] < key[v]){
ch[u][] = merge(ch[u][], v);
pushup(u);
return u;
}
else{
ch[v][] = merge(u, ch[v][]);
pushup(v);
return v;
}
}
void split_a(int u, int a, int& x, int& y){
if(!u){ x = y = ; return; }
if(val[u] <= a){
x = u;
split_a(ch[u][], a, ch[u][], y);
}
else{
y = u;
split_a(ch[u][], a, x, ch[u][]);
}
pushup(u);
}
void split_k(int u, int k, int& x, int& y){
if(!u){ x = y = ; return; }
if(size[ch[u][]]+ <= k){
x = u;
split_k(ch[u][], k-size[ch[u][]]-, ch[u][], y);
}
else{
y = u;
split_k(ch[u][], k, x, ch[u][]);
}
pushup(u);
}
inline void Insert(int v){//以v进行分裂,插入后合并。
val[++num_node]= v;
key[num_node] = rand();
size[num_node] = ;
int a,b;
split_a(RooT, v, a, b);
RooT = merge(merge(a,num_node), b);
}
inline void Delete(int v){//以v进行分裂,删除后合并。
int a,b,c,d;
split_a(RooT, v, a, b);
split_k(a, size[a]-, c, d);
clear(d);
RooT = merge(c, b);
}
inline int Rank(int v){//以v-1进行分裂,看左侧树的size
int a,b,ans;
split_a(RooT, v-, a, b);
ans = size[a]+;
RooT = merge(a, b);
return ans;
}
inline int Kth(int k){//以k进行分裂,依旧看左侧的size,但注意再分裂一次取出比k小的
int a,b,c,d,ans;
split_k(RooT, k, a, b);
split_k(a,size[a]-,c,d);
ans = val[d];
RooT = merge(merge(c,d),b);
return ans;
}
inline int Pre(int v){//与kth同理
int a,b,c,d,ans;
split_a(RooT, v-, a, b);
split_k(a,size[a]-,c,d);
ans = val[d];
RooT = merge(merge(c,d),b);
return ans;
}
inline int Nxt(int v){
int a,b,c,d,ans;
split_a(RooT, v, a, b);
split_k(b, , c, d);
ans = val[c];
RooT = merge(a,merge(c,d));
return ans;
}
void PrintTree(int u){
if(ch[u][]) PrintTree(ch[u][]);
printf("%d ",val[u]);
if(ch[u][]) PrintTree(ch[u][]);
}
int main(){
// freopen(".in","r",stdin);
srand((unsigned)time(NULL));
N = read();
while(N--){
opt = read(), x = read();
if(opt == ) Insert(x);
if(opt == ) Delete(x);
if(opt == ) printf("%d\n", Rank(x));
if(opt == ) printf("%d\n", Kth(x));
if(opt == ) printf("%d\n", Pre(x));
if(opt == ) printf("%d\n", Nxt(x));
}
return ;
}
「FHQ Treap」学习笔记的更多相关文章
- Fhq Treap [FhqTreap 学习笔记]
众所周知 Fhq Treap 是 fhq 神仙研究出来的平衡树- 具体实现 每个点实现一个 \(\text{rnd}\) 表示 rand 的值 为什么要 rand 呢 是为了保证树高为 \(\log ...
- Note -「Lagrange 插值」学习笔记
目录 问题引入 思考 Lagrange 插值法 插值过程 代码实现 实际应用 「洛谷 P4781」「模板」拉格朗日插值 「洛谷 P4463」calc 题意简述 数据规模 Solution Step 1 ...
- Note -「动态 DP」学习笔记
目录 「CF 750E」New Year and Old Subsequence 「洛谷 P4719」「模板」"动态 DP" & 动态树分治 「洛谷 P6021」洪水 「S ...
- Note -「单位根反演」学习笔记
\(\mathcal{Preface}\) 单位根反演,顾名思义就是用单位根变换一类式子的形式.有关单位根的基本概念可见我的这篇博客. \(\mathcal{Formula}\) 单位根反演的 ...
- 「Manacher算法」学习笔记
觉得这篇文章写得特别劲,插图非常便于理解. 目的:求字符串中的最长回文子串. 算法思想 考虑维护一个数组$r[i]$代表回文半径.回文半径的定义为:对于一个以$i$为回文中心的奇数回文子串,设其为闭区 ...
- 「线性基」学习笔记and乱口胡总结
还以为是什么非常高大上的东西花了1h不到就学好了 线性基 线性基可以在\(O(nlogx)\)的时间内计算出\(n\)个数的最大异或和(不需要相邻). 上述中\(x\)表示的最大的数. 如何实现 定义 ...
- 「Link-Cut Tree」学习笔记
Link-Cut Tree,用来解决动态树问题. 宏观上,LCT维护的是森林而非树.因此存在多颗LCT.有点像动态的树剖(链的确定通过$Access$操作),每条链用一颗$splay$维护.$spla ...
- 「AC自动机」学习笔记
AC自动机(Aho-Corasick Automaton),虽然不能够帮你自动AC,但是真的还是非常神奇的一个数据结构.AC自动机用来处理多模式串匹配问题,可以看做是KMP(单模式串匹配问题)的升级版 ...
- 【Java】「深入理解Java虚拟机」学习笔记(1) - Java语言发展趋势
0.前言 从这篇随笔开始记录Java虚拟机的内容,以前只是对Java的应用,聚焦的是业务,了解的只是语言层面,现在想深入学习一下. 对JVM的学习肯定不是看一遍书就能掌握的,在今后的学习和实践中如果有 ...
随机推荐
- Android 之文件夹排序
按文件名排序 /** * 按文件名排序 * @param filePath */ public static ArrayList<String> orderByName(String fi ...
- 解决OracleOraDb10g_home1TNSListener服务无法启动
造成OracleOraDb10g_home1TNSListener服务无法启动可能有三种情况: listener.ora文件配置有错误导致无法启动 相关环境变量没设置好 删除客户端时导致服务端相关注册 ...
- jmeter使用TCP请求时,乱码问题,字符集设置
不墨迹,直接上干货.(提示:UTF-8一个汉字占3个字节) TCP请求默认发的是GBK字符集,要想修改成UTF-8,只需要修改bin目录下的jmeter.properties文件,其中tcp.char ...
- spring笔记----看书笔记
上周末看了一章以前javaee轻量级的书spring部分,简单做了一些笔记 // ApplicationContext ac=new ClassPathXmlApplicationContext(&q ...
- 利用Navicat高效率postgresql转mysql数据库
本人很喜欢postgresql数据库,也一直认为postgresql比mysql要更好更强大. 可生态环境太差了,无奈,最近要把一个小站转成mysql数据库. 小站主要表数据110万,pg_dump备 ...
- C#几个经常用到的字符串的截取
string str="123abc456";int i=3;1 取字符串的前i个字符 str=str.Substring(0,i); // or str=str.Remov ...
- 【Python实战】模块和包导入详解(import)
1.模块(module) 1.1 模块定义 通常模块为一个.py文件,其他可作为module的文件类型还有".pyo".".pyc".".pyd&qu ...
- ARTS打卡第四周
Algorithm 只出现一次的数字 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次.找出那个只出现了一次的元素. 说明: 你的算法应该具有线性时间复杂度. 你可以不使用 ...
- 你所不知道的ASP.NET Core MVC/WebApi基础系列(一)
前言 最近发表的EF Core貌似有点多,可别误以为我只专攻EF Core哦,私下有时间也是一直在看ASP.NET Core的内容,所以后续会穿插讲EF Core和ASP.NET Core,别认为你会 ...
- vue兄弟之间传值 bus中央事件总线
创建一个eventVue.js文件 import Vue from 'vue' export default new Vue 父 <template> <div> <di ...