前置知识
你首先要学会的:
- RMQ ( S T 表 ) \text{RMQ}(ST \text{表}) RMQ(ST表)
- 分块
- 线段树
- 二进制,位运算
前记
我们把 RMQ \text{RMQ} RMQ 和分块 所解决的问题搬出来:
- 在长度为 n n n 的数组上, T T T 组询问 [ l , r ] [l,r] [l,r] 区间的 和(差,异或等有结合律的算术)。
显然我们已经有了一个 O ( n log n ) − O ( 1 ) \mathcal{O}(n \log n) - \mathcal{O}(1) O(nlogn)−O(1) 的算法。
思考
现在做一个 简单 的加强, n , T ≤ 2 × 1 0 7 n,T \leq 2 \times 10^7 n,T≤2×107.
你会发现预处理的时间不够了。
很显然,我们考虑朴素的分块怎么做。
将数组分为若干个长度为 b b b 的块,对于每个块,处理块内答案,前缀块的答案,后缀块的答案。
当 b = n b = \sqrt{n} b=n 时 取到最平均的答案,可以 O ( n ) − O ( n ) \mathcal{O}(n) - \mathcal{O}(\sqrt{n}) O(n)−O(n),但显然不行。
那考虑 RMQ \text{RMQ} RMQ 呢?用 f i , j f_{i,j} fi,j 表示 [ i , i + 2 j − 1 ] [i , i + 2^j-1] [i,i+2j−1] 区间的答案,倍增处理即可。显然是 O ( n log n ) − O ( 1 ) \mathcal{O}(n \log n) - \mathcal{O}(1) O(nlogn)−O(1).
这两个算法都无法通过 2 × 1 0 7 2 \times 10^7 2×107 如此庞大的数据。我们思考一个新的算法。
基于分块
首先考虑分块基础上的优化。同样 处理块内答案,前缀块的答案,后缀块的答案,这里是 O ( n ) \mathcal{O}(n) O(n) 的,考虑如何优化询问。
询问分两种情况:
- 横跨多个块
- 包含在一个块内
显然,第一种情况我们可以把 横跨的整块 进行前缀计算,然后转为 对两侧不完整快的计算,即剩余两个部分各自包含在一个完整的块内。这样做是 O ( 1 ) \mathcal{O}(1) O(1) 的,但如何计算第二种方案?
考虑如何处理一个块内的方案,如果按照 分块的暴力思想,那么 O ( n ) \mathcal{O}(\sqrt{n}) O(n) 就奠定了。显然这不是我们想要的。
现在的问题转为,在长度为 n \sqrt{n} n 的数组上,