【前言(一堆废话)】
目前 OI 竞赛中两大主流平衡树之一就是 FHQ Treap(另一个是 Splay)。
普通 BST 的中序遍历中,val 值构成一个单调递增的序列。
Treap 在 BST 的基础上,维护了一个 key 值,使其 val 满足 BST 性质,key 满足 Heap 性质。在维护 Heap 性质的同时,使 Treap 的树高期望是 log(n)。通常情况下,key 值是随机的。
普通的 Treap 通过旋转维护 Heap 性质,实现简单且性能优越,相关资料也很广泛,这里就不在赘述。
FHQ Treap,又称 非旋 Treap,函数式 Treap。由神犇FHQ首先提出(OrzOrzOrz)。函数式编程的思想,使其可以实现持久化。

【核心操作】
FHQ Treap 有两个核心操作,split 和 merge。
split 的作用是将一棵树分裂成两部分,其中左半部分的子树 size == k。
其实也可以按结点 val 值分裂,这样就可以完成普通平衡树的操作。

void split(int o, int k, int &x, int &y) { // 将根为 o 的树分裂成以 x, y 为根的两棵树,其中 x 的子树大小为 kif (!o) { x = y = 0; return; } // o 不存在, 返回int c = t[t[o].lc].size; // o 左子树大小push_down(o); // 先把维护的信息下推if (c < k) { // 左子树 size 不够,递归到右子树处理x = o; split(t[o].rc, k - c - 1, t[o].rc, y);}else { // 左子树 size 以能满足要求,递归到左子树处理y = o;split(t[o].lc, k, x, t[o].lc);}push_up(o); // 分裂完成后,信息上推
}

merge 操作的作用是将两棵树合并,返回合并后的根节点

int merge(int x, int y) { // 合并以 x, y 为根的两棵树,返回合并后的根节点if (!x || !y) return x | y; // 其中一棵为空树,返回非空的树if (t[x].key < t[y].key) { // 维护小根堆push_down(x);t[x].rc = merge(t[x].rc, y); // 递归处理,注意要保证中序遍历 x 在 y 左边push_up(x);return x;}else {push_down(y);t[y].lc = merge(x, t[y].lc);push_up(y);return y;}
}

通过这两个操作可以完成任何 Splay 能够完成的操作。
例题:洛谷 P3391 【模板】文艺平衡树
每次 split 出 [1,l - 1],[l,r],[r + 1,n] s三个区间,再打上反转标记。

【其他操作】
父指针:通常情况下,FHQ Treap不用维护父指针。如果一定要维护也没问 题。只需在 push_up 函数中加上

if (lc) t[lc].fa = o; // 注意无左(右)子树的情况
if (rc) t[rc].fa = o;

在 split 后,将分裂出的子树父指针清空

t[u].fa = t[v].fa = 0; // 分裂出以 u, v 为根的子树

建树:最简单的,暴力插入建树

for (int i = 1; i <= n; i++) root = merge(root, new_node(i));

时间复杂度O(nlogn)),已经很优秀。但在某些时候会成为性能瓶颈。

考虑到 key 值满足笛卡尔树的性质,所以可以用同样的思路建树。
用单调栈维护树的最右链,注意要维护左右子树指针,同时 push_up。

int build(int *a, int k) { // 以 a[] 中 [1, k] 建树int root = 0;memset(s, 0, sizeof s); // 清空栈for (int i = 1, x, y; i <= k; ++i) {x = new_node(a[i]), y = 0;while (top && t[x].key < t[s[top]].key) { y = s[top--]; push_up(y); }s[++top] = x;t[x].lc = y;if (top) t[s[top - 1]].rc = x;if (top == 1) root = x; // 维护根结点}while (top) push_up(s[top--]);return root;
}

时间复杂度 O(n),与 Splay 建树持平

【优缺点】
优点:代码短,易实现。不用旋转。拓展性强。
缺点:作为 LCT 的辅助树时,时间复杂度比 Splay 多一个 log。

【可持久化】
等我学了在写。。。

【经典题目】
略。。。

FHQ Treap 总结相关推荐

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

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

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

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

  3. FHQ Treap 详解

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

  4. Treap + FHQ Treap

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

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

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

  6. FHQ TREAP 学习总结

    F H Q T R E A P FHQ \ TREAP FHQ TREAP P r e p a r e K n o w l e d g e Prepare \ Knowledge Prepare Kn ...

  7. 【模板】FHQ Treap

    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 [ ...

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

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

  9. FHQ Treap学习记录(详解)

    前言:嘻嘻,本蒟蒻的第一篇文章!由于本蒟蒻第一次写博客,本文章质量可能不是很好QAQ 前置芝士(了解即可啦~):C++.BST 二叉搜索树.堆.二叉堆 如果您不想听蒟蒻胡扯 Treap,可以直接根据目 ...

最新文章

  1. Leetcode 231. 2的幂 解题思路及C++实现
  2. 解决Vue打包后背景图片路径错误问题
  3. The most important part of the body
  4. java访问远程共享文件
  5. 亚马逊标题自动抓取_如何为您的家人提供自动Amazon礼品卡津贴
  6. react 最佳入门_miaov-React 最佳入门
  7. python同步两张数据表_Python 如何实现数据库表结构同步
  8. 如何使用webrtc 一
  9. Spring WebAppInitializer without web.xml
  10. HM个性化Recommendations--kaggle推荐比赛
  11. 微信小程序 flex:1表示什么
  12. java100以内依个_使用Java多线程实现任务分发
  13. php 日期format不要零_DateFormat PHP Class (php 处置日期)
  14. Ubuntu系统配置花生壳内网穿透
  15. 硬件工程师七夕鹊桥设计锦集
  16. LT8522EX 是 Lontium 的矩阵开关芯片基于两路输入,输出 (VGA 和 HDMI)
  17. clearcase下的一些常用命令
  18. JAVA后端面经总结
  19. 英伟达Quadro RTX A5000/A4000显卡系统参数曝光
  20. L2-032 彩虹瓶 (25 分) (栈操作)

热门文章

  1. Servlet - Java Web Core Component
  2. 2022CCPC广州 L. Station of Fate gym104053L
  3. 2016-03-30 作业 朱宇飞
  4. Delphi中的线程类--之(2)
  5. sh shell实现自动杀死cpu占用最高的pid,同时当cpu超过95%自动重启apache
  6. HBase的协处理器(Coprocessor)、HBase如何使用二级索引、observer协处理器、 endpoint协处理器、Hbase 协处理器加载方式
  7. jssdk 获取微信收货地址_微信JSSDK获取当前地理位置信息
  8. Lombok 插件安装、使用
  9. Csharp日常笔记
  10. CSharp-基础-集合的使用