倍增思想经典例题。。。
RMQ即区间最值问题,此题以最大值为例
设F[ i ] [ j ] 表示数组A中下标在 [ i , i + 2^j - 1 ]的区间最大值,递推边界 F [ i ] [ 0 ] = a [ i ];
在递推时,将子区间长度成倍增长,有公式F [ i ] [ j ] = max { F [ i ] [ j - 1 ] , F [ i + 2^( j - 1 ) ] [ j - 1 ] },即长度为2^j的子区间的最大值是左右两半长度为2 ^ ( j - 1 )的子区间的最大值中较大的一个
一些优化:
位运算
O(n)预处理Log数组会比使用cmath库的log2函数快
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10, lgN = 20;
int n, m;
int x, y;
int a[N], lg[N] = {-1}, f[N][lgN];
inline int read() /* 快读 */
{
int x = 0, f = 1;
char ch = getchar();
while (!isdigit(ch))
f = (ch == '-') ? -1 : 1, ch = getchar();
while (isdigit(ch))
x = x * 10 + (ch - '0'), ch = getchar();
return x * f;
}
int main()
{
n = read(), m = read();
for (int i = 1; i <= n; i++) /* 读入,边界处理,Log数组预处理 */
a[i] = read(), f[i][0] = a[i], lg[i] = lg[i >> 1] + 1;
for (int j = 1; j <= lg[n]; j++) /* 倍增跳RMQ */
for (int i = 1; i <= n - (1 << j) + 1; i++)
f[i][j] = std::max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
while (m--)
{
x = read(), y = read();
int k = lg[y - x + 1]; /* 自行思考这样覆盖的原因(其实没有什么东西要思考) */
std::cout << std::max(f[x][k], f[y - (1 << k) + 1][k]) << '\n';
}
return 0;
}