重修 分散层叠算法(Fractional Cascading)


新学的知识不能算重修了吧

自己想到的一个类似的东西:

顺势疗法(homeopathy):首先,把某种物质在酒精中浸泡几个星期,过滤浸泡液得到该物质的“母酊剂”。然后,使用一些母酊剂通过用水反复地稀释和强烈的摇动,得到最终的药剂。直到现在,仍然用相同的基本的基本程序来制造顺势疗法的药剂。

最后得到的药剂往往甚至不含有原始物质的一个分子,正统的科学认为,这会致使药剂失去活性。

生物化学博士方舟子曾撰写《“分子顺势疗法”来了》一文:

市场上销售的顺势疗法药物常见的有用蒸馏水把药物稀释了 \(10^{30}\) 的。这是什么概念呢?往海洋里滴一滴水,也不过被稀释了 \(10^{26}\),也就是说,其有效成分的浓度,比沧海一粟还要低 \(1\) 万倍,事实上是什么都没有。根据阿芙伽德罗定律,\(1\) 摩尔的任何物质包含有大约 \(10^{24}\) 个分子,也就是说,稀释到 \(10^{24}\) 以后,已不可能含有被稀释的成分的一个分子,全都是水分子了。

学完后你就会发现分散层叠算法和这个过程很像不过不是伪科学

P6466 分散层叠算法(Fractional Cascading)

record

还是讲一下大体:

题面

给出 \(k\) 个长度为 \(n\)升序数组。保证所有数组中出现过的数不重复(如果有的题重复,离散化即可)。
现在有 \(q\) 个查询:给出数 \(x\)分别求出每个数组中大于等于 \(x\) 的最小的数(lower_bound)(不存在则定义为 \(0\))。
由于不让瓶颈在 IO 上,每个查询输出 \(k\) 个后继的异或和。
还是由于不让瓶颈在 IO 上,只要编号为 \(d\) 倍数的询问要输出。
强制在线
\(O(nk+q(k+\log n))\) 时间 \(O(nk)\) 空间内解决。

题解

我们先设原 \(k\) 个序列为 \(A^{(1)},A^{(2)},\dots,A^{(k)}\)

对应地,创建 \(k\) 个序列 \(B^{(1)},B^{(2)},\dots,B^{(k)}\),但是每个元素实现中不只是一个 int,存有两个下标 \(nxt1,nxt2\),意义后面说。

初始化

文中有序数组之间的 \(+\) 均定义为归并

\[B^{(k)}=A^{(k)} \]

之后 \(s\) 遍历 \((k-1)\to 1\),每一步中:

\(C\) 数组为 \(B^{(s+1)}\) 提取偶数下标元素得到的数组。

\[B^{(s)}=A^{(s)}+C \]

归并的同时 \(B^{(s)}\) 中每个元素 \(x\) 记录:

  • \(nxt1\)\(x\)\(A^{(s)}\) 中的 lower_bound 下标。

  • \(nxt2\)\(x\)\(B^{(s+1)}\) 中的 lower_bound 下标。注意是 \(B^{(s+1)}\) 而不是 \(C\)

因为

\[\frac{\frac{\frac{\ddots}{2}+n}{2}+n}{2}+n=2n \]

所以 \(B^{(s)}\) 数组长度的上界是 \(2n\),所以空间 \(O(nk)\) 满足。

由于归并是线性复杂度的,初始化时间为 \(O(nk)\)

询问

设询问的值在 \(B^{(1)}\) 中的 lower_bound 下标为 \(p\)注意是 \(B\) 而不是 \(A\)

\(s\) 遍历 \(1\to k\)

  1. \(p\) 位置 \(O(1)\) 微调。(虽然这一步在 \(s=1\) 无用,但后面有)

  2. \(pos=B^{(s)}_p.nxt1\)\(A^{(s)}_{pos}\) 统计入答案(本题 \(\text{xor}\))。

  3. \(p:=B^{(s)}_p.nxt2\),此时 \(p\) 可能不是 \(B^{(s+1)}\) 正确的 lower_bound,但是下一轮循环开始时会有微调。由于 \(C\)\(B\) 隔位取位得来的,所以当前的 \(p\) 与真正的 \(p\) 之间相差不超过 \(1\),所以第一步的微调 \(O(1)\) 得证。

全过程记得特判 \(p\)\(B^{(s)}\) 界的情况。

单次询问的时间复杂度是 \(O(\log n+k)\)(第一次 lower_bound + 后面 \(k\) 次微调)