FHQ Treap


无旋Treap

维护的信息

c h [ i ] [ 0 / 1 ] ch[i][0/1] ch[i][0/1] v a l [ i ] val[i] val[i] f i x [ i ] fix[i] fix[i] s i z [ i ] siz[i] siz[i] t o t tot tot
左右儿子 权值 随机修正权值 以 i i i 为根的子树节点数 节点总数
r t rt rt x x x y y y z z z
根节点编号 临时子树编号 临时子树编号 临时子树编号

类定义

class FHQ_Treap {private:
#define ls(k) ch[k][0]
#define rs(k) ch[k][1]int ch[maxn][2], val[maxn], fix[maxn], siz[maxn], tot;int rt, x, y, z;
public:
}T;

操作

基本操作

m a i n t a i n ( x ) maintain(x) maintain(x) : 更新节点 x x x 的 s i z siz siz 值

n e w ( v ) new(v) new(v) : 新建一个权值为 v v v 的节点

void maintain(int x) { siz[x] = siz[ls(x)] + siz[rs(x)] + 1; }
int New(int v) {val[++tot] = v;fix[tot] = rand();siz[tot] = 1;return tot;
}

核心操作

分裂

S p l i t ( i , k , x , y ) Split(i,k,x,y) Split(i,k,x,y) : 当前节点为 i i i ,按权值 k k k 将其分为 x x x , y y y 两个子树, x x x , y y y 为两个子树的根节点编号 (注: x x x 与 y y y 需要加引用,这样分裂操作才可以修改 c h ch ch 来做到正确维护)

  • 若当前节点为 0 0 0 ,则说明为空,令 x = y = 0 x = y =0 x=y=0 ,返回
  • 当前节点 v a l < = k val <= k val<=k ,则其左子树都可以放在 x x x 上,继续在右子树中寻找
  • 当前节点 v a l > k val > k val>k ,则其右子树都可以放在 y y y 上,继续在左子树中寻找
  • 寻找完后维护子树大小
void Split(int i, int k, int& x, int& y) {if(!i) x = y = 0;else {if(val[i] <= k) {x = i;Split(rs(i), k, rs(i), y);}else {y = i;Split(ls(i), k, x, ls(i));}maintain(i);}
}

合并

M e r g e ( x , y ) Merge(x,y) Merge(x,y) : 将子树 x x x , y y y 合并,并返回根节点编号(其中 x x x 子树的值小于等于 y y y 子树)

  • 若有一个子树为空,则返回 x ∣ y x\,|\,y x∣y ,及非空的子树
  • 通过比较 x x x 与 y y y 的 f i x fix fix 值,确定位置
int Merge(int x, int y) {if(!x || !y) return x | y;if(fix[x] > fix[y]) { //在堆中,x 在 y 的上方,值小于 y ,所以在 y 的左上方rs(x) = Merge(rs(x), y); // x 的右子树与 y 合并maintain(x);return x;}else { //在堆中,x 在 y 的下方,值小于 y ,所以在 y 的左下方ls(y) = Merge(x, ls(y)); // x 和 y 的左子树合并maintain(y);return y;}
}

插入操作

i n s e r t ( v ) insert(v) insert(v) : 插入一个权值为 v v v 的节点

  • 按 v v v 将树分裂
  • 让 x x x 与新节点合并,再与 y y y 合并
void insert(int v) {Split(rt, v, x, y);rt = Merge(Merge(x, New(v)), y);
}

删除操作

d e l ( v ) del(v) del(v) : 删除权值为 v v v 的节点

  • 分裂两次,一次按 v v v ,一次按 v − 1 v - 1 v−1
  • 将 y y y 的根删除(将左右子树合并即可)
  • 将三颗子树合并
void del(int v) {Split(rt, v, x, z);Split(x, v - 1, x, y);y = Merge(ls(y), rs(y));rt = Merge(Merge(x, y), z);
}

查询排名

r a n k ( v ) rank(v) rank(v) : 查询值 v v v 的排名

  • 按 v − 1 v - 1 v−1 分裂,子树 x x x 的大小 + 1 +1 +1 即为答案(不可按 v v v 划分,可能有重复)
int rank(int v) {Split(rt, v - 1, x, y);int ret = siz[x] + 1;rt = Merge(x, y);return ret;
}

按排名查值,前驱,后继

k t h ( x , v ) kth(x,v) kth(x,v) : 返回子树 x x x 中排名为 v v v 的下标

int kth(int x, int k) {while(1) {if(k <= siz[ls(x)])x = ls(x);else if(k == siz[ls(x)] + 1)return x;else k -= siz[ls(x)] + 1, x = rs(x);}
}

K t h ( k ) Kth(k) Kth(k) : 排名为 k k k 的数

int Kth(int k) {return val[kth(rt, k)];
}

p r e ( v ) pre(v) pre(v) : 值 v v v 的前驱

  • 按照 v − 1 v - 1 v−1 分裂, x x x 中排名最大的节点即为 v v v 的前驱
int pre(int v) {Split(rt, v - 1, x, y);int ret = val[kth(x, siz[x])];rt = Merge(x, y);return ret;
}

n x t ( v ) nxt(v) nxt(v) : 值 v v v 的后继

  • 按照 v v v 分裂, y y y 中排名最小的节点即为 v v v 的后继
int nxt(int v) {Split(rt, v, x, y);int ret = val[kth(y, 1)];rt = Merge(x, y);return ret;
}

【模板】普通平衡树
【模板】普通平衡树(数据加强版)

#include <bits/stdc++.h>
#define maxn 1000005
using namespace std;
int read() {int ret = 0, f = 1;char ch = getchar();while (!isdigit(ch)) {if (ch == '-')f = -1;ch = getchar();}while (isdigit(ch)) {ret = (ret << 1) + (ret << 3) + (ch ^ '0');ch = getchar();}return ret * f;
}
class FHQ_Treap {private:
#define ls(k) ch[k][0]
#define rs(k) ch[k][1]int ch[maxn][2], val[maxn], fix[maxn], siz[maxn], tot;int rt, x, y, z;void maintain(int x) { siz[x] = siz[ls(x)] + siz[rs(x)] + 1; }int New(int v) {val[++tot] = v;fix[tot] = rand();siz[tot] = 1;return tot;}void Split(int i, int k, int& x, int& y) {if (!i) x = y = 0;else {if (val[i] <= k) {x = i;Split(rs(i), k, rs(i), y);}else {y = i;Split(ls(i), k, x, ls(i));}maintain(i);}}int Merge(int x, int y) {if (!x || !y) return x | y;if (fix[x] < fix[y]) {rs(x) = Merge(rs(x), y);maintain(x);return x;}else {ls(y) = Merge(x, ls(y));maintain(y);return y;}}
public:void insert(int v) {Split(rt, v, x, y);rt = Merge(Merge(x, New(v)), y);}void del(int v) {Split(rt, v, x, z);Split(x, v - 1, x, y);y = Merge(ls(y), rs(y));rt = Merge(Merge(x, y), z);}int kth(int x, int k) {while (1) {if (k <= siz[ls(x)])x = ls(x);else if (k == siz[ls(x)] + 1)return x;else k -= siz[ls(x)] + 1, x = rs(x);}}int rank(int v) {Split(rt, v - 1, x, y);int ret = siz[x] + 1;rt = Merge(x, y);return ret;}int Kth(int k) {return val[kth(rt, k)];}int pre(int v) {Split(rt, v - 1, x, y);int ret = val[kth(x, siz[x])];rt = Merge(x, y);return ret;}int nxt(int v) {Split(rt, v, x, y);int ret = val[kth(y, 1)];rt = Merge(x, y);return ret;}
}T;
int n, opt, x;
int main() {srand(time(NULL));n = read();for (int i = 1; i <= n; i++) {opt = read(), x = read();if (opt == 1) T.insert(x);if (opt == 2) T.del(x);if (opt == 3) cout << T.rank(x) << endl;if (opt == 4) cout << T.Kth(x) << endl;if (opt == 5) cout << T.pre(x) << endl;if (opt == 6) cout << T.nxt(x) << endl;}return 0;
}

可持久化

让FHQ Treap可持久化,只需要在操作时复制节点,以便不影响之前的版本

复制节点

c o p y n o d e ( x ) copynode(x) copynode(x) : 复制节点 x x x

int copynode(int x) {val[++tot] = val[x]; siz[tot] = siz[x]; fix[tot] = fix[x];ls(tot) = ls(x); rs(tot) = rs(x);return tot;
}
void split(int i, int k, int& x, int& y) {if (!i)x = y = 0;else {if (val[i] <= k) {x = copynode(i);split(rs(x), k, rs(x), y);maintain(x);}else {y = copynode(i);split(ls(y), k, x, ls(y));maintain(y);}}
}
int Merge(int x, int y) {if (!x || !y)return x | y;if (fix[x] < fix[y]) {int p = copynode(x);rs(p) = Merge(rs(p), y);maintain(p); return p;}else {int p = copynode(y);ls(p) = Merge(x, ls(p));maintain(p); return p;}
}

r t → r t [ i ] rt \rightarrow rt[i] rt→rt[i] 来记录不同版本的根节点

【模板】可持久化平衡树

#include<bits/stdc++.h>
#define maxn 500005
using namespace std;
inline int read() {int ret = 0, f = 1;char ch = getchar();while (!isdigit(ch)) {if (ch == '-')f = -1;ch = getchar();}while (isdigit(ch)) {ret = (ret << 1) + (ret << 3) + (ch ^ '0');ch = getchar();}return ret * f;
}
int rt[maxn];
class FHQ_Treap {private:
#define ls(x) ch[x][0]
#define rs(x) ch[x][1]int ch[maxn * 50][2];int siz[maxn * 50], fix[maxn * 50], val[maxn * 50];int tot;inline int copynode(int x) {siz[++tot] = siz[x]; fix[tot] = fix[x]; val[tot] = val[x];ch[tot][0] = ch[x][0]; ch[tot][1] = ch[x][1];return tot;}inline void maintain(int x) {siz[x] = siz[ls(x)] + siz[rs(x)] + 1;}inline int New(int x) {val[++tot] = x; siz[tot] = 1; fix[tot] = rand();return tot;}inline int Merge(int x, int y) {if (!x || !y)return x | y;if (fix[x] < fix[y]) {int p = copynode(x);rs(p) = Merge(rs(p), y);maintain(p); return p;}else {int p = copynode(y);ls(p) = Merge(x, ls(p));maintain(p); return p;}}inline void split(int i, int k, int& x, int& y) {if (!i)x = y = 0;else {if (val[i] <= k) {x = copynode(i);split(rs(x), k, rs(x), y);maintain(x);}else {y = copynode(i);split(ls(y), k, x, ls(y));maintain(y);}}}
public:inline void Delete(int& root, int v) {int x = 0, y = 0, z = 0;split(root, v, x, z);split(x, v - 1, x, y);y = Merge(ls(y), rs(y));root = Merge(Merge(x, y), z);}inline void Insert(int& root, int v) {int x = 0, y = 0, z = 0;split(root, v, x, y);root = Merge(Merge(x, New(v)), y);}inline int kth(int k, int v) {if (v == siz[ls(k)] + 1)return val[k];else if (v <= siz[ls(k)])return kth(ls(k), v);else return kth(rs(k), v - siz[ls(k)] - 1);}inline int rank(int& root, int v) {int x, y;split(root, v - 1, x, y);int ans = siz[x] + 1;root = Merge(x, y);return ans;}inline int pre(int& root, int v) {int x, y, k, ans;split(root, v - 1, x, y);if (!x)return -2147483647;k = siz[x];ans = kth(x, k);root = Merge(x, y);return ans;}inline int nex(int& root, int w) {int x, y, ans;split(root, w, x, y);if (!y)return 2147483647;else ans = kth(y, 1);root = Merge(x, y);return ans;}
}T;
int n;
int main() {n = read();for (register int i = 1, opt, v, tim; i <= n; ++i) {tim = read(), opt = read(), v = read();rt[i] = rt[tim];if (opt == 1) T.Insert(rt[i], v);else if (opt == 2) T.Delete(rt[i], v);else if (opt == 3) printf("%d\n", T.rank(rt[i], v));else if (opt == 4) printf("%d\n", T.kth(rt[i], v));else if (opt == 5) printf("%d\n", T.pre(rt[i], v));else printf("%d\n", T.nex(rt[i], v));}return 0;
}

【模板】FHQ Treap相关推荐

  1. 模板 - FHQ - treap 无旋平衡树

    整理的算法模板合集: ACM模板 目录 FQH - treap 无旋平衡树 按权值分裂 按排名分裂 文艺平衡树 可持久化序列 FQH - treap 无旋平衡树 operator 1 : 插入一个数 ...

  2. FHQ Treap 详解

    0. 简单介绍 FHQ Treap,以下简写为fhq,是一种treap(树堆)的变体,功能比treap强大,代码比splay好写,易于理解,常数稍大. fhq不需要通过一般平衡树的左右旋转来保持平衡, ...

  3. FHQ Treap 总结

    [前言(一堆废话)] 目前 OI 竞赛中两大主流平衡树之一就是 FHQ Treap(另一个是 Splay). 普通 BST 的中序遍历中,val 值构成一个单调递增的序列. Treap 在 BST 的 ...

  4. Treap + FHQ Treap

    一:Treap 支持:插入.删除.查询 x x x 的排名.查询排名为 x x x 的数.查前驱.查后继.左旋右旋 模板题:P3369 [模板]普通平衡树 #include<bits/stdc+ ...

  5. FHQ Treap【基于P3369的讲解】【随机数、各数组、函数运用】

    该模板题的题目链接 很多人看到了FHQ Treap都不知道它是干什么用的,今天也是刚学的FHQ Treap,学了一整天了,终于过掉了洛谷的P3369了,也算是对这个算法有了些自己的了解,还是错的太多次 ...

  6. FHQ Treap及其可持久化与朝鲜树式重构

    FHQ Treap,又称无旋treap,一种不基于旋转机制的平衡树,可支持所有有旋treap.splay等能支持的操作(只有在LCT中会比splay复杂度多一个log).最重要的是,它是OI中唯一一种 ...

  7. P2596 [ZJOI2006]书架(fhq treap)

    P2596 [ZJOI2006]书架 我们用fhq treap来完成这一题 对于一个新插入的节点我们取权值为其索引值,其所记录的valuevaluevalue是其当前索引所在位置. 操作一:把索引为v ...

  8. 可持久化平衡树(FHQ Treap)

    两个最基本的操作 merge合并 split分割 merge 把两棵treap合并成一棵treap,要满足T1最大值要比T2最小值小,比较将随机数值key值更大的作为合并后的根 假设T1作为根节点作为 ...

  9. 平衡树学习笔记之 fhq Treap

    平衡树学习笔记 1:fhq Treap(非旋 Treap) 正文开始前首先 %%% fhq 大佬. 众所周知,平衡树是一种 非常猥琐 码量堪忧的数据结构. 他的祖先是一种叫做二叉搜索树 ( B S T ...

最新文章

  1. 每天一记 10.01.27
  2. SQL基础整理——例题
  3. APP技巧:电脑登录微信,要删除这5个文件!否则别人能查看聊天记录
  4. 为什么引入devops_DevOps可以为您的文档做什么?
  5. 丹琦女神的对比学习新SOTA,在中文表现如何?我们补充实验后,惊了!
  6. nodejs mysql 增删改查_#NodeJS# MySQL的介绍安装使用以及使用NodeJS链接MySQL实现增删改查...
  7. 黑苹果卡在苹果logo_黑苹果的历史
  8. java rtf_Java中存取Rtf文件 | 学步园
  9. 海康sip服务器是什么意思_sip协议端口有什么作用?sip端口号详解
  10. html的size属性,HTML size属性用法及代码示例
  11. Windows下装ubuntu系统
  12. 删除页面引入的js或者css文件
  13. 教您用数学课件制作工具演示线变二面角
  14. 飞上“云端”的OA系统:什么是OA系统的云端化?
  15. 计算机回收站设置大小,win10系统修改回收站存储位置和大小的操作办法
  16. java搭建o2o平台_java版 spring cloud+mybatis 构建 b2b2c o2o 多租户电子商务平台
  17. 制作视频剪辑,自动剪辑视频的软件如何剪辑
  18. antd Modal
  19. 黑马程序员 XAML概述
  20. LED的行业术语及详解

热门文章

  1. 盘点拿些出身最奇特的程序员是什么样的?
  2. 并发策略-CAS算法
  3. Linux Shell 并行
  4. 【数据结构】数据结构是什么
  5. LocalSend - 文件传输工具
  6. 什么是死锁,如何避免死锁?
  7. 【OBS-WEBRTC】obs-output 集成libwebrtc 采坑
  8. ARM SMMU的原理与IOMMU[转载]
  9. 单片机时钟周期、状态周期、机器周期、指令周期的理解
  10. csharp c++