do_while_true's blog

晚风中闪过 几帧从前啊

0%

「学习笔记」区间半群信息查询

qwaszx 博客 的抄写。

半群信息可以简单理解为有结合律的信息。比方说 $\gcd,\min,\max,+,\times$ 之类的。

这一部分的东西在 OI 中没什么用,就当学个乐吧()

猫树 和 Sqrt Tree 可能有些用。

朴素做法

$\Theta(n^2)$ 预处理所有区间的答案,然后可以 $\Theta(1)$ 询问。

线段树 树状数组 ST 表

只要是半群信息都可以用线段树维护。而树状数组则要求信息可以差分,ST 表要求是幂等半群信息($x\circ x=x$)。

猫树

考虑线段树上分治,对于每个端点代表的区间 $[l,r]$ 及其中点 $m$,预处理区间内所有以 $m$ 为结尾的后缀信息和以 $m+1$ 为起点的前缀信息。那么每次查询 $[l,r]$ 的区间信息的时候,只需要定位到 $[l,r]$ 第一次分裂的节点,也就是 $l,r$ 节点的 LCA,那么就可以 $\Theta(1)$ 查询了。

那就可以把序列补成 $2$ 的次幂,这样 LCA 就相当于定位到 $l,r$ 的二进制下的 lcp,可以 $\Theta(1)$ 求得。

把序列补成 $2$ 的次幂还要考虑空的位置要为幺元,不存在的幺元的话,直接钦点一个幺元,合并的时候特判一下就好了。(被 qyc 教育了)

预处理时间复杂度 $\Theta(n\log n)$,单次询问 $\Theta(1)$.

Sqrt Tree

把序列按照 $\sqrt n$ 分块,对于整块之间的答案,可以用上文的朴素做法 $\Theta(n)$ 预处理,散块也可以 $\Theta(n)$ 预处理块内前缀信息和后缀信息。这样跨块的询问都能 $\Theta(1)$ 询问,块之内的递归下去处理即可。

递归层数是 $T(n)=T(\sqrt n)+\Theta(1)=\Theta(\log \log n)$ (每次递归指数 $/2$),询问的话和上节一样,定位需要用到 LCA,合并是预处理的三个信息进行合并。

时间复杂度 $\Theta(n\log \log n)-\Theta(1)$.

Sqrt Tree 还能 $\mathcal{O}(\sqrt n)$ 单点修改,这个先咕着,也有可能单独再写个文章专门写 Sqrt Tree。

在 Sqrt Tree 中块间的预处理中,使用朴素做法并进行复杂度平衡,得到了 Sqrt Tree。类似地,块间可以使用猫树维护,为了复杂度平衡,采用 $\log n$ 为块长。这样每次递归下去问题规模变为 $\Theta(\log n)$,树高为 $\Theta(\log^{\ast}n)$,时间复杂度就是 $\Theta(n\log^{\ast}n)-\Theta(1)$.

Extend

没有更好的理解,只能进行抄写。

在上节中,用猫树维护 Sqrt Tree 得到了一个树高为 $\Theta(\log^{\ast}n)$ 的数据结构。那么可以继续对上述过程进行迭代:假设上一层数据结构深度为 $T(m-1,n)$,那么以 $T(m-1,n)$ 分块,块间用上一层数据结构进行维护,块内递归处理。这一层数据结构的深度就是不断令 $n\gets T(m-1,n)$ 直到 $n=\Theta(1)$ 的次数。

为了找到最优的复杂度,考虑找到最小的 $m$ 使得 $T(m,n)=\Theta(1)$,通过查表(不知道 qwaszx 咋查的)发现 $m$ 就是反阿克曼函数 $\alpha(n)$.

考虑每次询问以 $\Theta(1)$ 的复杂度进入上一层数据结构,则询问复杂度为 $\Theta(\alpha(n))$;预处理的时候,在第 $m$ 层的数据结构需要花费 $\mathcal{O}(nT(m,n))$ 的时空复杂度进入到规模(也就是分块的块数)为 $\mathcal{O}(nT(m,n)/T(m-1,n))$ 的下一层数据结构,因此预处理的时空复杂度为 $\mathcal{O}(n\alpha (n))$(这里 qwaszx 说是查表查出来的),总时间复杂度为 $\mathcal{O}((n+q)\alpha(n))$.

qwaszx 说这个是下界,但我并不知道原论文是啥()