跳转至

高效处理无修改区间询问的方法

高效处理无修改区间询问的方法

问题描述

给出一个某种元素的序列\(a_1,a_2,\dots,a_n\),要求进行\(m\)次询问,每一次是询问一段区间\([l,r]\)的某种支持结合律和快速合并的信息。

要求复杂度尽量优秀,假设合并复杂度为\(O(1)\)

以下的时间复杂度\(O(A)+O(B)+O(C)\)表示预处理复杂度、单次询问的复杂度和空间复杂度。

各种性质的具体问题

可减信息,如区间和、区间异或和

直接用前缀和实现,复杂度\(O(n)+O(1)+O(n)\)

可重复贡献信息,如区间最值

如果序列很长,使用线段树即可,复杂度\(O(n)+O(\log n)+O(n)\)

如果询问很多,但序列不是特别长,可以用倍增的RMQ,复杂度\(O(n\log n)+O(1)+O(n\log n)\)

如果序列很长,询问也很多,可以对序列线性建立笛卡尔树转为LCA问题,然后转为正负1RMQ,每\(\log n\)分一段打表预处理,复杂度\(O(n)+O(1)+O(n)\)。(这个还不是太懂)

仅满足支持结合律和快速合并,如最大子段和、区间的串哈希值

一般使用线段树实现,复杂度\(O(n)+O(\log n)+O(n)\)

以上内容摘录自ImmortalCO

对于第三类具体问题,询问的复杂度不够优秀,那么有什么解决方案呢?

离线

如果可以将询问离线,我们有一种基于分治的做法。考虑分治树的结构,每个节点代表一个区间\([L,R]\)。对于一个询问\([l,r]\)​,我们可以找到分治树上一个最小的完全包含它的区间(具体实现可以\(O(1)\)求分治树上的LCA),把这个询问挂在对应的节点上。在分治到每个区间时,求出以分治中心\(mid\)为开头和结尾的信息,就可以\(O(1)\)处理挂在这个区间上的询问了。我们得到了一个预处理复杂度\(O(n\log n)\),离线\(O(1)\)询问的做法。

实际上,这场的J题也是类似的思想,当时还想了好久。

在线

思想是相同的,但需要储存下预处理的信息,空间复杂度也是\(O(n\log n)\)​​。这个东西叫做猫树,本质上是记录下分治的过程。ImmortalCO在原文中的解释是考虑询问\([l,r]\)在线段树上定位的过程,是在哪个节点\(p\)中同时递归到左右两个儿子。仔细思考可以发现这跟分治的本质相同。

猫树的拓展

直接引用ImmortalCO原话:

考虑把猫树扩展到树上,以资磁快速的链上信息询问。我们对树进行点分治,预处理所有点到重心的信息(需要保存“包括中心”和“不包括重心”两种信息,如果有方向要求要专门考虑),这样同样能拆成两个已经预处理的信息的和。询问的时候,我们需要找出这条链上最上面的重心。对点分治建立点分树(把重心连成树),然后我们要找到的重心就是询问的链端点的 LCA,这可以用倍增 RMQ 来预处理。

写完才发现好像只是搬运了一下文章,自己没写什么内容,不过写都写了,还是发一下算了。