zoukankan      html  css  js  c++  java
  • RMQ原理及实现

      RMQ(Range Minimum/Maximum Query),区间最值查询问题,是指:对于长度为n的数列A,回答若干次询问RMQ(i,j),返回数列A中下标在区间[i,j]中的最小/大值。

      这里介绍Tarjan的Sparse-Table算法,预处理时间为O(nlogn),但查询只需要O(1),并且常数很小,算法也很容易写出。

     1)预处理:

      设A[i]是要求区间最值的数列,d[i, j]表示从第i个数起连续2^j个数中的最小值。(DP的状态)

      显然d[i][0]的值就是A[i](DP初值),我们把d[i,j]平均分成两段(因为d[i,j]一定是偶数个数字),从 i 到i + 2 ^ (j - 1) - 1为一段,i + 2 ^ (j - 1)到i + 2 ^ j - 1为一段(长度都为2 ^ (j - 1))。于是我们得到了状态转移方程d[i, j]=min(d[i,j-1], d[i + 2^(j-1),j-1]),代码实现如下(这里使用lrj蓝书代码):

    1 void RMQ_init(const vector<int> &A) {
    2     int n = A.size();
    3     for(int i = 0; i < n; ++i) d[i][0] = A[i];
    4     for(int j = 1; (1 << j) <= n; ++j) 
    5         for(int i = 0; i + (1 << j) - 1 < n; ++i) 
    6             d[i][j] = min(d[i][j - 1], d[i + (1 << (j - 1))][j - 1]);
    7 }

    2)查询:

      假如我们需要查询的区间为(i,j),那么我们需要找到覆盖这个闭区间(左边界取i,右边界取j)的最小幂(可以重复,比如查询1,2,3,4,5,5不是2的任意次方,但我们可以查询1234和2345)。

      这个查询长度我们取范围小于等于区间长度的最大(2^k),这样我们查询i到 i +(2^k)与j - (2^k) + 1到j的值,取二者最小值即可,代码实现如下:

    1 int RMQ(int L, int R) {
    2     int k = 0;
    3     while((1 << (k + 1)) <= R - L + 1) ++k;
    4     return min(d[L][k], d[R - (1 << k) + 1][k]);
    5 }
    版权声明:该博客版权归本人所有,若有意转载,请与本人联系
  • 相关阅读:
    vue 跳转路由传参数用法
    百度地图放大之后,多边形,矩形覆盖物消失
    百度地图画多边形,画圆, 监听事件不触发原因
    兄弟组件之间如何通信
    vue如何触发某个元素的单击事件?
    input 清空值。(转载)
    inline-block元素水平居中问题
    android 浏览器对图片加载高度渲染问题
    IE下png图片黑边问题
    IE css hack整理
  • 原文地址:https://www.cnblogs.com/fan-jiaming/p/9739281.html
Copyright © 2011-2022 走看看