RMQ - 区间最大值问题
倍 增 + 动 规 预 处 理 数 组 f [ i ] [ j ] 。 f [ i ] [ j ] : 以 i 为 起 点 , 长 度 为 2 j 的 区 间 里 的 最 大 值 。 状 态 转 移 方 程 f [ i ] [ j ] = m a x ( f [ i ] [ j − 1 ] , f [ i + 2 j − 1 ] [ j − 1 ] ) , 即 将 区 间 一 分 为 二 , 取 两 个 子 区 间 的 较 大 值 。 查 询 长 度 为 l e n 的 区 间 [ l , r ] 的 最 大 值 : 与 预 处 理 过 程 类 似 , 找 到 一 个 最 大 的 整 数 k , 使 得 2 k < = l e n , 那 么 两 个 长 度 为 2 k 的 区 间 必 能 覆 盖 长 度 为 l e n 的 区 间 。 答 案 仍 然 是 取 m a x ( f [ l ] [ k ] , f [ r − 2 k + 1 ] [ k ] ) 。 倍增+动规预处理数组f[i][j]。\\\ \\f[i][j]:以i为起点,长度为2^j的区间里的最大值。\\ \ \\状态转移方程f[i][j]=max(f[i][j-1],f[i+2^{j-1}][j-1]),即将区间一分为二,取两个子区间的较大值。\\ \ \\查询长度为len的区间[l,r]的最大值:\\与预处理过程类似,找到一个最大的整数k,使得2^k<=len,\\那么两个长度为2^k的区间必能覆盖长度为len的区间。\\答案仍然是取max(f[l][k],f[r-2^k+1][k])。 倍增+动规预处理数组f[i][j]。 f[i][j]:以i为起点,长度为2j的区间里的最大值。 状态转移方程f[i][j]=max(f[i][j−1],f[i+2j−1][j−1]),即将区间一分为二,取两个子区间的较大值。 查询长度为len的区间[l,r]的最大值:与预处理过程类似,找到一个最大的整数k,使得2k<=len,那么两个长度为2k的区间必能覆盖长度为len的区间。答案仍然是取max(f[l][k],f[r−2k+1][k])。
起 点 i 有 n 个 , 长 度 j 有 l o g 2 n 个 , 预 处 理 时 间 复 杂 度 O ( n l o g 2 n ) 。 起点i有n个,长度j有log_2n个,预处理时间复杂度O(nlog_2n)。 起点i有n个,长度j有log2n个,预处理时间复杂度O(nlog2n)。
例题:
输 入 长 度 为 n 的 序 列 a 1 , a 2 , . . . , a n 。 以 及 q 个 询 问 , 每 个 询 问 包 括 区 间 的 左 右 端 点 l , r , 对 每 个 询 问 输 出 区 间 最 大 值 。 输入长度为n的序列a_1,a_2,...,a_n。以及q个询问,每个询问包括区间的左右端点l,r,对每个询问输出区间最大值。 输入长度为n的序列a1,a2,...,an。以及q个询问,每个询问包括区间的左右端点l,r,对每个询问输出区间最大值。
数据范围:
1≤n≤2×100000,
1≤q≤10000
输入样例:
6
34 1 8 123 3 2
4
1 2
1 5
3 4
2 3
输出样例:
34
123
123
8
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=2e5+10;
int n,a[N],q,f[N][18];
void init()
{
for(int j=0;j<18;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
if(!j) f[i][j]=a[i];
else f[i][j]=max(f[i][j-1],f[i+(1<<j-1)][j-1]);
}
int query(int l,int r)
{
int len=r-l+1;
int k=log(len)/log(2);
return max(f[l][k],f[r-(1<<k)+1][k]);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
init();
scanf("%d",&q);
while(q--)
{
int l,r;
scanf("%d%d",&l,&r);
printf("%d\n",query(l,r));
}
return 0;
}