RMQ 是查询 给定区间 [ l , r ] 最值的.
不能修改,只能查! 注意下标就行了
以 Balanced Lineup 为例
#include<iostream>
using namespace std;
int n;
int max_num[10005][20];
int min_num[10005][20];
int d[10005];
void RMQ_init()
{
for(int i=1; 1<<i <= n ; i++ ) // <= n 区间长度 要 <= 总长度
for(int j=1; j+(1<<i)-1 <= n && j<=n ;j++) //求 从 j 开始,长度是 ( 1<<(i-1) )的区间 内的最值 取等条件的验证可以让 i =1 则 j 要能到 倒数第 2 个元素,
//j开始的 长度是 2^1 的区间
{ // 最重要的是这句话 起点+长度-1=终点 我从1 开始存 终点就是 n 从0 开始存 终点就是 n-1
max_num[j][i]=max(max_num[j][i-1],max_num[ j+(1<<(i-1)) ][i-1]); // 已知 起点,长度,求终点的下一个元素的下标, [a,b] 区间吧, b-a+1=1<<(i-1) b+1=a(起点)+长度
min_num[j][i]=min(min_num[j][i-1],min_num[ j+(1<<(i-1)) ][i-1]);
}
}
int RMQ(int l,int r)
{
int k=0;
while( (r-l+1) >= (1<< (k+1)/*1<< (k+1) 里面的 k+1 相当于试探一下 */ ) ) // 看看[l,r]区间有多长, 让 1<<k 尽量逼近 这个长度
{
k++;
}
int ma=max( max_num[l][k] , max_num[ r - (1<<k)+1 ][k] ); // 区间长度是k ,分两段来覆盖[l,r], 中间可以重叠,第二段,已知终点,已知长度,就能知道 第二段的起点
int mi=min( min_num[l][k] , min_num[ r - (1<<k)+1 ][k] );
// cout<<"max : "<<ma<<" min: "<<mi<<endl;
return ma-mi ;
}
int main()
{
cin>>n;
int m; cin>>m;
for(int i=1;i<=n;i++)
cin>>d[i], max_num[i][0]=d[i],min_num[i][0]=d[i];
RMQ_init();
int l,r;
while( m--)
{
cin>>l>>r;
cout<<RMQ(l,r)<<endl;
}
return 0;
}