GESP8 · 倍增 / RMQ · 6/24 ST 表专课

P3865 ST 表 && RMQ

数组不改、反复查区间最大值:先预处理所有“2 的幂长度”的块,查询时用两个会重叠的大块拼出区间,O(1) 出答案。

一、先回答问题

结论

max 可以重叠,所以任意区间 [l,r] 都能被两个长度 2^k 的块盖住: 一个贴左端、一个贴右端,取两块最大值即可。

为什么不用线段树

本题没有修改、查询多达 2×10⁶ 次。ST 表查询严格 O(1), 比线段树 O(log n) 更稳,是静态区间最值的天花板。

二、核心观察

预处理 + 查询

预处理st[i][j] = 从 i 起、长 2ʲ 的区间最大值。 一个长 2ʲ 的块 = 左右两个长 2ʲ⁻¹ 的块:st[i][j]=max(st[i][j-1], st[i+2^(j-1)][j-1])

查询 [l,r]:令 k=⌊log2(r-l+1)⌋, 答案 = max(st[l][k], st[r-2^k+1][k])。两块都长 2^k,必定盖满且可重叠。

三、互动演示:两个 2ᵏ 块拼出 [l,r]

数组(下标 1~8):9 3 1 7 5 6 0 8。查询区间 [2,7],长度 6。

左块 st[l][k] 右块 st[r-2ᵏ+1][k] 两块重叠

四、自己选答案

Q1. ST 表能用“两块重叠”查询,靠的是什么性质?

Q2. 查询 [2,7](长 6),应取 k = ?

Q3. 下面哪种问法 不能直接用这套“两块重叠”?

五、手推结果

步骤取值结果
区间长度r-l+1 = 7-2+1 = 6k=⌊log2 6⌋=2,2ᵏ=4
左块 [l, l+2ᵏ-1][2,5] = {3,1,7,5}max = 7
右块 [r-2ᵏ+1, r][4,7] = {7,5,6,0}max = 7
max(7, 7)答案 = 7

六、C++14 参考代码

倍增预处理 + O(1) 查询
① 2×10⁶ 次询问必须用快读,否则 cin 会 TLE。
② 右块起点是 r-2^k+1(贴右端),别写成 l+2^k
lg[] 预处理出每个长度的 log2,查询时直接查表更快。

七、接着练(同梯度)