zoukankan      html  css  js  c++  java
  • [数据结构-查询区间最小值小结(RMQ问题(Range Minimum Query))]

    查询区间第k大可以用划分树,而查询区间最小(最大)值可以用代码更简单的Sparse-Table(ST)算法(Tarjan发明)。

    原理很简单,代码也很短:

    令d(i,j)表示从i开始的,长度为2^j的一段元素最小值,那么可以用递推方法计算:

    d(i,j) = min( d(i,j-1) , d(i+2^(j-1) , j-1) )

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

    查询操作也很简单。查询区间[L,R]内最小值:令k为满足2^k<=R-L+1的最大整数,则以L开头、以R结尾的两个长度为2^k的区间合起来就覆盖了整个[L,R]区间。

    int RMQ(int L,int R) {
        int k=0;
        while((1<<(k+1))<=R-L+1) k++;
        return min(d[L][k],d[R-(1<<k)+1][k]);
    }

    下面的代码预处理了mm数组,它表示k的值,所以速度更快:

    const int MAXN = 50010;
    int dp[MAXN][20];
    int mm[MAXN];
    //初始化RMQ, b数组下标从1开始,从0开始简单修改
    void initRMQ(int n,int b[])
    {
        mm[0] = -1;
        for(int i = 1; i <= n; i++)
        {
            mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1];
            dp[i][0] = b[i];
        }
        for(int j = 1; j <= mm[n]; j++)
            for(int i = 1; i + (1<<j) -1 <= n; i++)
                dp[i][j] = max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
    }
  • 相关阅读:
    Spring IOC知识点一网打尽
    Spring中-IOC-Bean的初始化-循环依赖的解决
    原型模式(Prototype)
    生成器模式
    工厂模式
    单例模式
    查询性能优化
    索引
    sql游标的使用入门
    js和C#中的编码和解码
  • 原文地址:https://www.cnblogs.com/lastone/p/5275963.html
Copyright © 2011-2022 走看看