// //

数据结构——RMQ

   RMQ

  今天临放学前终于是学会了RMQ,特此写一篇题解来缅怀

  RMQ是一种数据结构,用途是查询区间内最大值或最小值

或者你所要求的任意条件,主要思想是二进制的思想,其中还用到了dp的思想,

是一种非常不错的算法,在确定左右区间查询上时间复杂度优于线段树

但是NOIP并不常用,也算为后面的LCA打一个基础

  给一道题:

 

  n个数,m个询问,每次询问区间[L,R]内的最小值。

 

  思路:我们需要一个二维数组来存储信息,存储方式是dp[i][j]

其中i代表查询的左端点,j为 查询范围 是i+2^j范围内的最小值,数列本身定为a[i]

我们首先确定dp[i][0]一定就是a[i]本身,这是显然的,然后我们需要找出dp转移方程

那方程是什么呢?

 

  首先我们确定区间为给出的l,r,区间范围就是r-l+1,我们可以将区间

一分为二,然后分别找到左边和右边的最小值,取两值的min值便是区间所求

那我们可以得出结论:dp[i][j]=min(dp[i][j-1],dp[i+(1<<j-1)][j-1])

解释一下,dp[i][j]为从i开始2^j为范围中的最小值,即为我们所求dp[i][j-1]

从i开始2^(j-1)范围内的最小值,是所求范围的前一半

dp[i+(1<<j-1)][j-1] ,从i开始2^(j-1)范围内的最小值,是所求范围的后一半

 

  然后我们还需要注意一点,就是在预处理dp数组时我们需要将i放在里层

j放在外层,因为我们是以i为开始点进行dp的,在长度为2^j时我们需要把每一个

可出发的i都处理好,所以要将j放在外层

 

  最后就是区间查询了,我们需要一个值为log2(r-l+1),代表我们的j,这个式子

就是我们还原区间的方式,我们j代表的是2^j,那自然还原就是log2回去了

  代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 int n,m,x,y,k;
 4 long long a[100010];
 5 long long dis[100010][20];
 6 inline void rmq(){
 7     for(register int i=1;i<=n;i++) dis[i][0]=a[i];
 8     for(register int j=1;(1<<j)<=n;j++)
 9     for(register int i=1;i+(1<<j)-1<=n;i++)//将i放在里层因为咱们要先更新每一个i的位置关系 
10     dis[i][j]=min(dis[i][j-1],dis[i+(1<<j-1)][j-1]);
11     return;
12 }
13 inline void search(int l,int r){
14     k=log2(r-l+1);
15     printf("%lld\n",min(dis[l][k],dis[r-(1<<k)+1][k]));
16     return;
17 }
18 int main(){
19     scanf("%d%d",&n,&m);
20     for(register int i=1;i<=n;i++) scanf("%lld",&a[i]);
21     rmq();//预处理 
22     for(register int i=1;i<=m;i++){
23         scanf("%d%d",&x,&y);
24         search(x,y); 
25     }
26     return 0;
27 }
RMQ

  end;

posted @ 2019-06-13 21:10  Zafkiel  阅读(368)  评论(6编辑  收藏  举报
Live2D //博客园自带,可加可不加