题解:洛谷 P3865 【模板】ST 表 & RMQ 问题
【题目来源】
洛谷:P3865 【模板】ST 表 & RMQ 问题 - 洛谷
【题目描述】
给定一个长度为 \(N\) 的数列,和 \(M\) 次询问,求出每一次询问的区间内数字的最大值。
【输入】
第一行包含两个整数 \(N,M\),分别表示数列的长度和询问的个数。
第二行包含 \(N\) 个整数(记为 \(a_i\)),依次表示数列的第 \(i\) 项。
接下来 \(M\) 行,每行包含两个整数 \(l_i,r_i\),表示查询的区间为$ [l_i,r_i]$。
【输出】
输出包含 \(M\) 行,每行一个整数,依次表示每一次询问的结果。
【输入样例】
8 8
9 3 1 7 5 6 0 8
1 6
1 5
2 7
2 6
1 8
4 8
3 7
1 8
【输出样例】
9
9
7
7
9
8
7
9
【算法标签】
《洛谷 P3865 ST表 & RMQ问题》 #st表# #O2优化#
【代码详解】
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 100005; // 定义数组最大长度
const int MAX_LOG = 22; // 最大对数级别
int n, m; // n: 数组长度, m: 查询次数
int f[MAX_N][MAX_LOG]; // ST表,f[i][j]表示区间[i,i+2^j-1]的最大值
int main()
{
// 输入数组长度和查询次数
cin >> n >> m;
// 输入原始数组数据
for (int i = 1; i <= n; i++)
scanf("%d", &f[i][0]); // 初始化ST表第一层
// 预处理ST表
for (int j = 1; j <= 20; j++) // 枚举区间长度(2^j)
{
for (int i = 1; i + (1 << j) - 1 <= n; i++) // 枚举区间起点
{
// 状态转移:合并左右两个子区间
f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
}
}
// 处理查询
for (int i = 1; i <= m; i++)
{
int l, r;
scanf("%d%d", &l, &r); // 输入查询区间
// 计算区间长度的对数
int k = log2(r - l + 1);
// 查询区间最大值:取两个覆盖区间的最大值
printf("%d\n", max(f[l][k], f[r - (1 << k) + 1][k]));
}
return 0;
}
【运行结果】
8 8
9 3 1 7 5 6 0 8
1 6
9
1 5
9
2 7
7
2 6
7
1 8
9
4 8
8
3 7
7
1 8
9
浙公网安备 33010602011771号