综述

有时我们会遇见一些题目,这些题目看起来很适合使用莫队算法处理,但是他们的单次转移并非是 的,这时直接使用莫队即使调整块长,也会导致复杂度不正确。

此时,如果每次转移对答案的贡献可以进行差分,我们就可以将这些转移拆开离线下来,使用其它算法批量处理。

我们用 表示 关于 产生的贡献。

如我们在将当前区间 扩展到 时,我们要求的是 。如果可以差分,我们可以将其写成 ,其中第一项我们可以对于每个 都预处理出来,后一项我们可以把每个这样的项都离线存到对应的 上,然后从小到大枚举并扫描线处理。其它几个转移的方向也都可以类似地处理。

这一在莫队这个离线算法上,将转移再次离线处理的算法叫做莫队二次离线。

我们结合实际题目来理解。

例题

给你一个长为 的序列 次询问,每次查询一个区间的逆序对数。

数据范围:

直接莫队每次转移至少是 的,观察可以发现我们每次转移要求的信息是「一个数在某个区间内的排名」,而这一信息关于区间可以差分,因此考虑二次离线。

我们将 拓展到 ,要求的是 在 区间内有多少比 大的数。 我们用 表示 区间内比 大的数, 表示 区间内比 小的数。则答案的变化量可以写作

同理 缩小至 的变化量可以写作 拓展到 可以写作 , 缩小至 可以写作

对于这些式子中的 ,我们可以使用树状数组提前 预处理出来;对于其余的 项,我们将 离线存在 进行批量处理。

这里有一个优化空间的技巧:我们发现处理每个询问时,离线到 上的 都是连续的一段,因此我们不需要把每次移动都存下,只需要存下调整的一段即可。这样我们的空间可以从总次数 下降到询问数

现在我们来处理我们二次离线下来的问题:向一个集合中加入数,查询一个数在集合中的排名。莫队总共移动端点的次数是 的,而数组总共只有 的长度,因此我们考虑使用 插入、 查询的值域分块解决这个问题。

至此,我们在 的时间复杂度和 的空间复杂度下解决了此题。

最后值得注意的是,我们求得的是每次的答案变化量而非答案本身,需要对其进行前缀和才能得到最终的答案。

多次询问区间中 中所有数的「Abbi 值」之和。

Abbi 值定义为:若 在询问区间 中是第 小,那么它的「Abbi 值」等于

我们不妨令 中比 大的数之和, 中比 大的数的数量,那么我们向右移动右端点时,产生的贡献为 ,其它几个方向可同理写出,在此不加赘述。

上式中的 依旧可以进行预处理,其余的离线到另一端点上,进行扫描线处理。不难发现我们要处理的依然是 次插入、 次询问排名的问题,因此同样使用值域分块解决。