【科技】单 $\log$ 合并两棵有交集 FHQ-Treap 的方法
维护可分裂 & 合并的可重集
考虑这样一个问题:
维护 \(n\) 个 可重集 \(S_1, S_2, \cdots, S_n\),元素值域为 \([1, U]\),初始集合为空。支持一下操作:
- 将 \(S_p\) 中 \(\in [x, y]\) 的所有元素 割离 出来并插入集合 \(S_q\) 中,注意不用复制;
- 将 \(S_q\) 中所有元素 合并 到 \(S_p\) 中并将 \(S_q\) 清空;
- 计算 \(S_p\) 中 \(\in[x, y]\) 的元素个数;
- 求 \(S_p\) 中第 \(k\) 小的元素;
- 在 \(S_p\) 中插入 \(x\) 个 \(y\) 元素。
一共需要进行 \(Q\) 次操作。
一般的维护方法
动态开点权值线段树
这种问题最主流的做法,它可以方便支持以上所有操作。
时空复杂度都是 \(O(n\log n)\)。
平衡树
主要会用 FHQ-Treap 来写,因为 split 和 merge 操作非常方便。
一般来说合并会使用启发式合并,每次都是小的到大的合并,可以证明每个元素最多被合并 \(O(\log n)\) 次。于是时间复杂度为 \(O(n\log^2 n)\),但是平衡树只需要 \(O(n)\) 的空间。
\(O(\log n)\) 的有交集平衡树合并
这里使用 FHQ-Treap 作为维护的数据结构。这个 \(O(\log n)\) 一次是均摊的,然而我并不会这个证明。
先放一个 评测结果(I/O 优化,O2)。这个排在时间最优解第一页,去掉 I/O 优化的话空间用的也很少。因为这是一个优秀的 \(O(n\log n)\) 时间,\(O(n)\) 空间的优秀做法。
我们发现上面平衡树的解法的瓶颈在于合并,然而这好像并没有优化余地。于是尝试设计一个新的合并思路。在这里感谢 Mr_Spade 给我介绍这个(并不算非常复杂的)科技。
考虑现在有两棵 Treap,根为 \(x, y\)。我们先比较两个结点的随机值,钦定随机值小的作为当前的根。这里假定为 \(x\)。然后我们需要搞出 \(x\) 的左右子树,分别为两棵 Treap 并集(除去 \(x\))中 \(< x\) 和 \(>x\) 的权值的结点构成的 Treap(\(=x\) 的可以特殊处理)。
对于 \(x\),显然它的左右子树(\(l_1, r_1\))就满足上面那个要求;而对于 \(y\) 我们则可以直接按 \(x\) 的权值 split,得到 \(l_2, r_2\) 两棵树。
最后我们发现这是一个可以递归处理的问题,因为我们再对 \(l_1, l_2\)、\(r_1,r_2\) 分别做这样的合并即可,两次合并的结果就可以作为 \(x\) 的两个子树。
参考代码实现:
int join(int x, int y) {
if (!x || !y) return x | y; // 有一个空间的即可返回
if (t[x].pty > t[y].pty) swap(x, y); // 取随机权值小的作为根
int L1 = t[x].ch[0], R1 = t[x].ch[1], L2 = 0, R2 = 0, equ = 0; // x 直接是左右子树
split(y, t[x].val, L2, R2), split(L2, t[x].val - 1, L2, equ); // y 按权值 split
if (equ) t[x].cnt += t[equ].siz, t[x].siz += t[equ].siz; // 相等特殊处理
t[x].ch[0] = join(L1, L2), t[x].ch[1] = join(R1, R2); // 递归合并
return pushup(x), x; // 更新信息
}
实际上这样常数并不大,在空间优于线段树的同时也不会比线段树慢。注意 rand() 很慢,使用不建议每次都随机一下。
后记
- 原文地址:https://www.cnblogs.com/-Wallace-/p/13865869.html
- 本文作者:@-Wallace-
- 转载请附上出处。
【科技】单 $\log$ 合并两棵有交集 FHQ-Treap 的方法的更多相关文章
- SQL中合并两个表的JOIN语句
SQL里有四种JOIN语句用于根据某条件合并两个表: (INNER) JOIN: 交集 LEFT (OUTER) JOIN: 左表数据全包括,右表对应的如果没有就是NULL RIGHT (OUTER) ...
- 如何在Node.js中合并两个复杂对象
通常情况下,在Node.js中我们可以通过underscore的extend或者lodash的merge来合并两个对象,但是对于像下面这种复杂的对象,要如何来应对呢? 例如我有以下两个object: ...
- 剑指Offer面试题:16.合并两个排序的链表
PS:这也是一道出镜率极高的面试题,我相信很多童鞋都会很眼熟,就像于千万人之中遇见不期而遇的人,没有别的话可说,唯有轻轻地问一声:“哦,原来你也在这里? ” 一.题目:合并两个排序的链表 题目:输入两 ...
- 【java基础】 合并两个类型相同的list
将两个类型相同的list合并,可以用 addAll(Collection<? extends E> c) import java.util.ArrayList; import java.u ...
- 合并两个结构完全相同的DataTable
两个结构一模一样的DataTable如何合并? 例子:使用Winform进行演示,表2的数据为固定的,表1的数据可以动态添加,通过合并按钮合并表1和表2的数据到表3 1.规定公共的DataTable结 ...
- LeetCode——Same Tree(判断两棵树是否相同)
问题: Given two binary trees, write a function to check if they are equal or not. Two binary trees are ...
- 合并两个有序数组a和b到c
问题:两个有序数组a和b,合并成一个有序数组c. // 合并两个有序数组a和b到c void Merge_Array(int a[], int n, int b[], int m, int c[]) ...
- Python合并两个numpy矩阵
numpy是Python用来科学计算的一个非常重要的库,numpy主要用来处理一些矩阵对象,可以说numpy让Python有了Matlab的味道. 实际的应用中,矩阵的合并是一个经常发生的操作,如何利 ...
- (剑指Offer)面试题17:合并两个排序的链表
题目: 输入两个递增排序的链表,合并这两个链表并使新链表中的结点仍然时按照递增排序的. 链表结点定义如下: struct ListNode{ int val; ListNode* next; }; 思 ...
随机推荐
- tcp 输入 prequeue以及backlog队列
/*ipv4_specific是TCP传输层到网络层数据发送以及TCP建立过程的真正OPS, 在tcp_prot->init中被赋值给inet_connection_sock->icsk_ ...
- Socket bind系统调用简要分析
主要查看linux kernel 源码:Socket.c 以及af_inet.c文件 1.1 bind分析 #include <sys/types.h> /* See NOTES */#i ...
- seaborn库中柱状图绘制详解
柱状图用于反映数值变量的集中趋势,用误差线估计变量的差值统计.理解误差线有助于我们准确的获取柱状图反映的信息,因此打算先介绍一下误差线方面的内容,然后介绍一下利用seaborn库绘制柱状图. 1.误差 ...
- Java(三)常用类
@ 目录 Java常用类 一.字符串相关的类 1.String类 2.StringBuffer类 3.StringBuilder类 二.JDK8以前的日期时间API 1.java.lang.Syste ...
- Python基础数据类型与for循环
数据类型:int,bool,str,list, tuple元组,dict字典. 1.数字:12,3,4 在使用print打印数字时,在终端界面中无法判断出打印的是什么类型,当我们需要知道一个值是什么类 ...
- python编码规范以及推导式的编写
一.python 的编码规范
- Dockerfile中如何自动回答标准输入的问题
前言大家在用docker build制作自己的image的時候,都会用RUN命令来执行一些操作来安装某些必须的软件. 而一些软件的安装过程中会需要用户来输入yes/no或者y/n来确定一些东西后才能进 ...
- Mysql预处理语句prepare、execute、deallocate
前言 做CTF题的时候遇到的所以参考资料学习一波.... MySQL的SQL预处理(Prepared) 一.SQL 语句的执行处理 1.即时 SQL 一条 SQL 在 DB 接收到最终执行完毕返回,大 ...
- 基于Pycharm的Python开发环境配置
基于Pycharm的Python开发环境配置 编辑于2020-11-18 Python安装 双击桌面的Python3.x安装包. 勾选Add to path. 方便起见,选择Install now.下 ...
- 关于GoldWave为Vegas制作音频交叉淡化特效的教程分享
在Vegas里对音频交叉淡化的处理,是通过将两段音频交叠.调整交叠部分的音量.选取交叉淡化类型这三步来实现的,许多步骤是在音频轨道拖动音量线来实现的,操作上不够灵敏精细.其实,单就音频的交叉淡化处理, ...