2025.10.3 闲话:分散层叠

10.3 闲话-分散层叠

这个东西好像没什么用,但是好像有有些用。

先看这么个问题:

给定 \(k\) 个长度为 \(n\) 的序列,\(m\) 次询问,每次询问 \(x\)\(k\) 个序列中的后继的异或和,强制在线

这东西有个显然的 \(O(mk\log n)\) 做法,但是我们可以寻求更优秀的算法。

分散层叠维护的就是这么个东西。

分散层叠是一种维护多序列二分的数据结构(也许吧)。

分散层叠需要维护一个数组 \(M_{i,j}\) 其中有三个值 \(\{val, now, nxt\}\) 分别表示值,该序列后继位置,\(M_{i+1}\) 中后继位置。

但是这时直接跳肯定假了,为啥?

因为前面可能还有合法的点呢,那么可以每隔一个将 \(M_{i+1}\) 中的元素插入 \(M_{i}\) 中,这是维护的 \(nxt\) 就是这写插入点中的后继位置了。

这时跳下去竟然合法点只有 \(nxt, nxt-1\) 两个点,为啥?

因为 \(nxt - 2\) 一定在 \(M_{i}\) 可是我们没有找到它,那么它就一定不是后继。

使用归并排序维护,查询先二分出 \(M_1\) 的位置。

复杂度 \(O(m(k+\log n))\),空间复杂度 \(O(2n)\)

这个分散层叠十分深刻的一点是它其实维护的是一个 \(DAG\) 结构,所以支持 \(DAG\) 上的链查询。

还有就是为什么要隔一个插一个,其实可以隔 \(p\) 个,这是也是没有问题的,可以做到时空复杂度平衡。

由于这东西本质上是维护的一个 \(DAG\) 那么线段树自然是能用的,每次将左右儿子的 \(\frac{1}{p}\) 个元素插入父节点,这样正常跳儿子容易发现还是对的。

这东西可以做一些大分块,比如第十分块加强版。

可以分块后多个块维护分散层叠,能做到 \(O(n\sqrt{n\log \log n})\),线段树底层分块加分散层叠做到 \(O(n\sqrt n)\)

修改暴力重构就行。

具体一点,首先如果正常分块,发现正好是多个块二分,那么就是正好的分散层叠,通过修改块长和步长可以做到 \(O(n\sqrt{n\log \log n})\)

但是咋能更优秀呢?

因为上述过程其实复杂度瓶颈被修改卡住了。

这时候就可以使用刚刚提到的线段树了,区间进行的加减法、推平等操作是不会更改分散层叠的本质的,那么直接对于那些会被更改形态的分散层叠暴力跑,这样如果将步长(\(p\))开到 \(3\) 此时求和竟然复杂度变成了 \(O(n\sqrt n)\)

posted @ 2025-10-03 22:06  QEDQEDQED  阅读(32)  评论(2)    收藏  举报