脑洞:对时间分块

众所周知,我们有过一些基于对时间倍增的暴力重构的想法,最经典的就是替罪羊树,动态 vector 等等。

另一角度有一些看似“二进制分组”的想法,例如算法导论上的一个用 ⌊ log ⁡ 2 n ⌋ \lfloor \log_2 n\rfloor log2n 个大小分别为 2 0 , 2 1 , … 2^0, 2^1, \dots 20,21, 的静态数组 Θ ( log ⁡ 2 n ) \Theta(\log^2n) Θ(log2n) 实现 set 的思路。被出成题的有“动态”AC自动机:CF710F。

简要地说,这是对于原本不易插入但多个结构易于合并查询结果的情况下的一种手段。但是如果重构的复杂度不似与时间相关的时候,就不妨把倍增改成分块。

比如说我们用这种方法重新做一下这个经典的问题:

区间修改

在一个长为 n n n 的数列上,一次操作要么是“区间加数”,要么是单点求值。

考虑一次修改,我们对其惰性执行,每发生 b b b 次修改,才将当前修改池里的操作用到数组上,重新 Θ ( n ) \Theta(n) Θ(n) 做一遍前缀和。

对于一次询问,我们首先查询预处理部分的数组,再加上未进行的那 Θ ( b ) \Theta(b) Θ(b) 个修改对答案的贡献。

复杂度为 Θ ( n ⋅ q b + q b ) \Theta(n\cdot \frac qb + qb) Θ(nbq+qb) ,在分块大小为 b = Θ ( n ) b = \Theta(\sqrt n) b=Θ(n ) 时达到最优 Θ ( q n ) \Theta(q\sqrt n) Θ(qn )。跑得和数列分块差不多。

接下来,我们来看一个本方法比较实用的题。

动态 FFT

单点修改一个数列,对 FFT 后的数列单点查询。保证数列长度是 2 的整次幂。
b b b 次做一次真正的 FFT。复杂度为 Θ ( n log ⁡ n ⋅ q b + q b ) \Theta(n\log n \cdot \frac qb + qb) Θ(nlognbq+qb),即达到 Θ ( q n log ⁡ n ) \Theta(q\sqrt{n\log n}) Θ(qnlogn )。(尽管这道题可以做到 Θ ( n log ⁡ n + q n ) \Theta(n\log n + q\sqrt n) Θ(nlogn+qn ),但是按时分块的做法也相当高效。)

其他妙用

还在思考,不知何时能得到

你可能感兴趣的:(研究)