# 稀疏表

• 求一个区间 [ l o w , h i g h ] [low,high] 内的最大值

## 构造稀疏表

#include <algorithm>

int n;
int arr[100000];
int sparse_table[100000][17];

void construct_sparse_table() {
for (int i = 0; i != n; i++) {
sparse_table[i][0] = arr[i];
}

for (int j = 1; (1 << j) <= n; j++) {
for (int i = 0; i + (1 << j) - 1 < n; i++) {
sparse_table[i][j] = std::max(sparse_table[i][j - 1], sparse_table[i + (1 << (j - 1))][j - 1]);
}
}
}

## 查询范围最大值

l = h i g h − l o w + 1 l=high-low+1 （即范围内的元素个数）， k = ⌊ log ⁡ 2 l ⌋ k=\lfloor\log_{2}l\rfloor

l − 2 k l-2^k 是因为总共有 l l 个元素，已经计算了 2 k 2^k 个元素，还差 l − 2 k l-2^k 个元素，这时只需要将范围整体往后移动 l − 2 k l-2^k 即可。

#include <algorithm>
#include <cmath>

int n;
int arr[100000];
int sparse_table[100000][17];

int range_maximum_query(int low, int high) {
int l = high - low + 1;
int k = static_cast<int>(std::floor(std::log2(l)));

return std::max(sparse_table[low][k], sparse_table[low + l - (1 << k)][k]);
}

## 洛谷P3865 ST表

#include <algorithm>
#include <cmath>
#include <iostream>

int n, m;
int arr[100000];
int sparse_table[100000][17];

int x = 0, f = 1;
char ch = getchar();

while (!isdigit(ch)) {
if (ch == '-') {
f = -1;
}
ch = getchar();
}

while (isdigit(ch)) {
x = x * 10 + ch - 48;
ch = getchar();
}

return x * f;
}

void construct_sparse_table() {
for (int i = 0; i != n; i++) {
sparse_table[i][0] = arr[i];
}

for (int j = 1; (1 << j) <= n; j++) {
for (int i = 0; i + (1 << j) - 1 < n; i++) {
sparse_table[i][j] = std::max(sparse_table[i][j - 1], sparse_table[i + (1 << (j - 1))][j - 1]);
}
}
}

int range_maximum_query(int low, int high) {
int l = high - low + 1;
int k = static_cast<int>(std::floor(std::log2(l)));

return std::max(sparse_table[low][k], sparse_table[low + l - (1 << k)][k]);
}

int main() {
std::cin >> n >> m;

for (int i = 0; i != n; i++) {
}

construct_sparse_table();

int l, r;
for (int i = 0; i != m; i++) {

std::cout << range_maximum_query(l - 1, r - 1) << "\n";
}
}
07-03 1万+

10-04 2631
09-15 44
03-28 527
01-27 261
04-21 1004
08-12 7359
12-06 177
07-20 817
08-09 1660
07-24 266
03-15 278
08-24 1507