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

考虑这样一个问题:

维护 \(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. 8、Spring Boot任务

    1.异步任务 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类任务,其实,在Spring ...

  2. Guitar Pro7应该怎么添加音色

    众所周知,音色是乐器的灵魂所在.音色的好坏,直接影响到了整首曲子的质量.Guitar Pro7中,用户不仅可以切换乐器模拟器,还能分别对其进行音色调整.对于新手而言,Guitar Pro7是一款非常合 ...

  3. 「CSP-S 2019」划分

    description loj 3212 solution 首先容易想到\(n^3\)DP,即令\(f_{i,j}\)表示前\(i\)个数的划分,其中最后一段是从\(j\)开始时的答案 于是有 \[f ...

  4. python字节自适应转化单位KB、MB、GB

    文件存储或者传输的过程中,经常需要展示传输文件的大小,或者传输量的大小,为了方便给人展示和阅读,编写一个简单的单位转换器. 1 def hum_convert(value): 2 units = [& ...

  5. 精尽 MyBatis 源码分析 - SqlSession 会话与 SQL 执行入口

    该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...

  6. 在iOS中使用ZBar扫描二维码和条形码

    最近做了个外包项目,里面用到了二维码扫描和微信支付!之前比较熟悉的是ZXing,但是在Xcode7.1里面发现竟然莫名的不支持,木有办法,从网上查了一下还有一种支持二维码扫描的东西,没错就是接下来我要 ...

  7. 对Tarjan——有向图缩点算法的理解

    开始学tarjan的时候,有关无向图的割点.桥.点双边双缩点都比较容易地理解了,唯独对有向图的缩点操作不甚明了.通过对luoguP2656_采蘑菇一题的解决,大致搞清了tarjan算法的正确性. 首先 ...

  8. 10种CSS3实现的loading动画,挑一个走吧?

    这篇文章主要介绍了10种CSS3实现的loading动画,帮助大家更好的美化自身网页,完成需求,感兴趣的朋友可以了解下. HTML: 1 <body> 2 <div class=&q ...

  9. mfc 双缓存

    CRect rect; //获取显示区域大小(该值为据对坐标,使用时需转换) GetWindowRect(rect); rect.SetRect(0, 0, rect.Width(), rect.He ...

  10. presto 访问kudu 多schemas配置

    presto需要访问kudu数据源,但是impala可以直接支持多数据库存储,但是presto不能原生支持,按照presto的官网设置了然而并不起作用. 官方文档: 到官方github提问了,然后并没 ...