zoukankan      html  css  js  c++  java
  • RMQ算法讲解

                                                        RMQ算法

    引入:
    例1、题目描述
    输入N个数和M次询问,每次询问一个区间[L,R],求第L个数到R个数之间的最大值。
     
    第一种方法:大暴力之术。 但是……时间复杂度最坏会达到 $O(NM)$,一半左右的点绝对爆T。
    所以,引入了————RMQ!
     
    RMQ:Range Maximum(Minimum) Query的缩写,顾名思义是用来求某个区间内的最大值或最小值,通常用在需要多次询问一些区间的最值的问题中。
     
    RMQ的原理是 动态规划
    用A[1..N]表示一组数,F[I,J]表示从A[I]到A[I+2^J-1]这个范围内的最大值,也就是以A[I]为起点连续2^J个数的最大值,由于元素个数为2^J个,所以从中间平均分成两部分,每一部分的元素个数刚好为2^(J-1)个,如下图:
                                         
    整个区间的最大值一定是左右两部分最大值的较大值,满足动态规划的最优原理
    状态转移方程:
    F[I,J]=max(F[I,J-1],F[I+2^(J-1),J-1])
    边界条件为F[I,0]=A[I]
    这样就可以在 $O(NlgN)$ 的时间复杂度内预处理F数组。
     
    预处理F数组代码:
    For i:=1 to n do f[I,0]:=a[i]
    for j:=1 to trunc(ln(n)/ln(2)) do begin  // 用到了换底公式,数学果然很重要
       for i:=1 to n+1-1 shl j do
         f[I,j]:=max(f[I,j-1],f[i+1 shl (j-1),j-1]) 
    End;
     
    对于询问[L,R],求出最大的x,满足2^x<=R-L+1,即x=trunc(ln(R-L+1)/ln(2))
    [L,R]=[L,L+2^x-1] ∪[R+1-2^x,R],两个子区间元素个数都是2^x个,如图
          
    ANS(L,R)=max(F[L,x],F[R+1-2^x,x])
    注意:在这里,RMQ在取最大最小值时,区间允许有重叠,但是求区间和的时候,坚决不能重叠,后果不用说。
     
    询问操作代码:
    Function query(L,R:longint):longint;
    Var x:longint;
    Begin
      x:=trunc(ln(R-L+1)/ln(2));
      exit(max(f[L,x],f[R+1-1 shl x,x]))
    End;
     
    该问题总时间复杂度为O(NlgN+M),避免了暴力超时的问题,而且一般比线段树$ (M*lgN) $略快。
     
     
     
     <Marvolo原创,严禁转载>
  • 相关阅读:
    烟台的两大建筑均初具规模,看一看现在的样子。
    ExpressBars Suite V6.29的安装
    又是一年返乡时,春运又开始了!
    C# 3.0新特性之扩展方法
    ObservableCollection<T> 类
    ControlTemplate和ItemTemplate的区别
    teechart属性和方法
    UpdateSourceTrigger 属性控制绑定源更新的执行时间
    "Lc.exe已退出 代码为1 "
    ObservableCollection 类
  • 原文地址:https://www.cnblogs.com/zhtjtcz/p/4991371.html
Copyright © 2011-2022 走看看