【科技】单 $\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; }; 思 ...
随机推荐
- C++ Split string into vector<string> by space(转)
c++中没有这么方便的实现,但也有很多的方法能实现这个功能,下面列出五种常用的实现的方法,请根据需要选择,个人觉得前三种使用起来比较方便,参见代码如下: #include <vector> ...
- 年轻人不讲武德来白piao我这个老同志
朋友们好啊,我是码农小胖哥. 今天有个同学问我在吗,我说什么事? 给我发个截图,我一看!噢,原来是帮忙搞个定时任务,还是动态的. 他说了两种选择,一种是用DelayQueue,一种是用消息队列. 他说 ...
- Ceph数据盘怎样实现自动挂载
前言 在Centos7 下,现在采用了 systemctl来控制服务,这个刚开始用起来可能不太习惯,不过这个服务比之前的服务控制要强大的多,可以做更多的控制,本节将来介绍下关于 Ceph的 osd 磁 ...
- Python_自动化测试_项目
<论坛自动化测试项目> 1.自行选择合适的社区 2.功能要求 5个以上,不包含登录页 3.多手动测试 多用selenium IDE 4.生成测试报告,发送邮件 5.计划任务定时完成 6 ...
- Python_字符串处理方法
1.字符串转换 #strcpy(sStr1,sStr2) sStr1 = 'strcpy' sStr2 = sStr1 sStr1 = 'strcpy2' print sStr2 1.字符串复制 #s ...
- python request 请求https报错问题
旁边大佬让我重新写一个某XX监控脚本 需要请求https遇到了如下的问题 花了一下午解决这个问题... 害太菜,.... 遇到的问题: requests.post 发送https请求的时候 ...
- 关于Redis的一些思考
1.从Java语言考虑,已经有ConcurrentHashMap等并发集合类了,与Redis相比,区别于差异在哪? 一直有这么个疑问,今天有搜了很久,很巧,搜到个有同样想法的问答,如下: When p ...
- FL studio系列教程(十七):FL Studio走带面板介绍
FL Studio走带面板主要是用来控制播放.录音以及调整歌曲速度的,除此之外还可以用来选择样本剪辑.下面就来详细地看一下这部分菜单. 1.样本/歌曲模式 样本/歌曲模式主要是用来切换样本和歌曲两种模 ...
- python接口测试4-数据库获取参数
首先确定需要传递的参数和接口,使用接口测试工具验证一下,接口和参数没有问题. 编写python接口脚本 import requests import unittest import json impo ...
- LeetCode周赛#206
1583. 统计不开心的朋友 #模拟 #暴力 题目链接 题意 有n为朋友,对每位朋友i,preference[i]包含 按亲密度从大到小 的朋友编号. 朋友们会被分为若干对,配对情况由pairs数组给 ...