维护可分裂 & 合并的可重集

考虑这样一个问题:

维护 \(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\) 次操作。

题目:Luogu P5494【模板】线段树分裂

一般的维护方法

动态开点权值线段树

这种问题最主流的做法,它可以方便支持以上所有操作。

时空复杂度都是 \(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() 很慢,使用不建议每次都随机一下。

后记

【科技】单 $\log$ 合并两棵有交集 FHQ-Treap 的方法的更多相关文章

  1. SQL中合并两个表的JOIN语句

    SQL里有四种JOIN语句用于根据某条件合并两个表: (INNER) JOIN: 交集 LEFT (OUTER) JOIN: 左表数据全包括,右表对应的如果没有就是NULL RIGHT (OUTER) ...

  2. 如何在Node.js中合并两个复杂对象

    通常情况下,在Node.js中我们可以通过underscore的extend或者lodash的merge来合并两个对象,但是对于像下面这种复杂的对象,要如何来应对呢? 例如我有以下两个object: ...

  3. 剑指Offer面试题:16.合并两个排序的链表

    PS:这也是一道出镜率极高的面试题,我相信很多童鞋都会很眼熟,就像于千万人之中遇见不期而遇的人,没有别的话可说,唯有轻轻地问一声:“哦,原来你也在这里? ” 一.题目:合并两个排序的链表 题目:输入两 ...

  4. 【java基础】 合并两个类型相同的list

    将两个类型相同的list合并,可以用 addAll(Collection<? extends E> c) import java.util.ArrayList; import java.u ...

  5. 合并两个结构完全相同的DataTable

    两个结构一模一样的DataTable如何合并? 例子:使用Winform进行演示,表2的数据为固定的,表1的数据可以动态添加,通过合并按钮合并表1和表2的数据到表3 1.规定公共的DataTable结 ...

  6. LeetCode——Same Tree(判断两棵树是否相同)

    问题: Given two binary trees, write a function to check if they are equal or not. Two binary trees are ...

  7. 合并两个有序数组a和b到c

    问题:两个有序数组a和b,合并成一个有序数组c. // 合并两个有序数组a和b到c void Merge_Array(int a[], int n, int b[], int m, int c[]) ...

  8. Python合并两个numpy矩阵

    numpy是Python用来科学计算的一个非常重要的库,numpy主要用来处理一些矩阵对象,可以说numpy让Python有了Matlab的味道. 实际的应用中,矩阵的合并是一个经常发生的操作,如何利 ...

  9. (剑指Offer)面试题17:合并两个排序的链表

    题目: 输入两个递增排序的链表,合并这两个链表并使新链表中的结点仍然时按照递增排序的. 链表结点定义如下: struct ListNode{ int val; ListNode* next; }; 思 ...

随机推荐

  1. 问题记录-CoordinatorLayout+WebView使用遇到的问题

    需求背景: 使用CoordinatorLayout+viewpager+tablayout+webview实现首页折叠效果. 使用问题: 在使用过程中首页的页面为原生/h5混合页,在原生页面正常,嵌套 ...

  2. BRT快速公交系统的可视化实践

    前言 随着城市进程的加快,中国城市机动车的数量飞速增长,造成城市交通拥堵问题越来越严重,城市居民对于改善出行条件的需求尤其是公共交通的便捷性问题也越来越迫切.而BRT(快速公交系统)作为一种新型的客运 ...

  3. Docker学习第二天(Docker容器管理)

    简介 emmmm Docker 容器管理 推荐文章:容器技术概述 run里面的子选项 1.使用run命令创建容器 docker container run -it ubuntu /bin/bash / ...

  4. webug第六关:这关需要rmb购买哦

    第六关:这关需要rmb购买哦 首先登陆,tom 123456 进行抓包改包

  5. tomcat安装证书https

    操作步骤(阿里云官网) 解压已下载保存到本地的Tomcat证书文件. 解压后您将看到文件夹中有2个文件,您可为两个证书文件重命名. 证书文件(domain name.pfx):以.pfx为后缀或文件类 ...

  6. (i春秋 Misc)ReCreators - CryMisc

    [i春秋 Misc] [题目链接] i春秋 Misc ReCreators CryMisc ReCreators 下载得到一个文件.老规矩,放入010文本编辑器中查看: 文件头是: KDMV 不清楚. ...

  7. java中对于浮点型数据操作

    java的基本数据类型-浮点型:单精度(float)和双精度(double). float:单精度浮点数在机内占4个字节.有效数字8位.表示范围:-3.40E+38 ~ +3.40E+38; doub ...

  8. JUC并发工具包之CountDownLatch

    1.介绍 本文将介绍CountDownLatch并给出实践中的几个例子,通过使用CountDownLatch我们可以让一个线程阻塞直到其他一个或多个线程执行完成. A synchronization ...

  9. leetcode 56合并区间 java

    //先排序,将左区间小的放在前面,然后如果前一个的右区间大于下一个的左区间,则可以合并,分别用两个下标指向当前的大区间和将要考察的小区间 class Solution {    public int[ ...

  10. Dynamics 365-表单元素取值/赋值

    取值/赋值 参考: 山人丶 提示: 查找类型赋值时需指定目标实体,记录名称及id值 时间和日期类型赋值时需赋值Date类型 //获取new_name的值(单行文本) Xrm.Page.getAttri ...