← 滑动窗口 · Sliding Window / 分块法:按 k 切块,预处理块内前缀 / 后缀最大值 待审核 4 / 7
Block / Sparse Table · 旁支

分块法:按 k 切块,预处理块内前缀 / 后缀最大值

双端单调队列面对同一个问题——定长窗口取最值——这里走另一条思路(和 sparse table 同源):把数组每 k 个切成一块。一个长度恰为 k 的窗口,在这种切法下要么正好是一整块,要么横跨相邻两块——绝不会缩在一块内部、也不会跨三块。于是只要预处理出两样东西,每次查询就是一次 max

两个预处理数组(各自在块内累积,跨块边界重置,做法类似前缀和):

  • rmax[i] = 从 i它所在块的结尾的最大值(后缀最大,从右往左推);
  • lmax[i] = 从它所在块的开头i 的最大值(前缀最大,从左往右推)。

窗口 [L, R] (R=L+k1R = L+k-1) 被块边界切成两截:左截 [L, 块尾] 的最大值正是 rmax[L],右截 [块头, R] 的最大值正是 lmax[R]——答案 = max(rmax[L], lmax[R])

1 · 为什么块大小恰好取 k?

块大小 = k 时,长度 k 的窗口最多只压在相邻两块上,两次查表就够。

  • 大于 k:窗口可能整段缩在一块内部,这块的 lmax/rmax 反映的是整块而非窗口,会算多 → 退回暴力;
  • 小于 k:窗口会横跨好几块,中间整块的最大值还得另外查(这正是 sparse table 用倍增块长 + 两段覆盖任意区间的动机)。

k 让「两段正好拼成窗口、不多不少」。

分块 / sparse table 这条路的独特价值:预处理一次后,它能 O(1)O(1) 回答任意区间的最值(不限定长 k),适合数组不变、反复查不同区间的静态场景;代价是不支持动态修改。要边改边查,得换线段树(见 区间查询系列)。而定长 k 且要流式处理时,单调队列开销更低。