RMQ 详解

 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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值