zoukankan      html  css  js  c++  java
  • RMQ问题ST算法与模板

    2007-07-15 15:48

    -------------------------------------算法简述-----------------------------------------

    ST算法O(nlogn)预处理,O(1)的查询指定区间的最值(以最小值为例)

    基本上是把待求区间[l,r]分为两段长为len的区间

    左边一段为[l,l+len-1],右边一段为[r-len+1,r]

    len必须使得两段区间覆盖待求区间

    设所求数组为w

    那么,所求最小值就是两个区间的最小值间的最小值

    即min(min{w[i],l<=i<=l+len-1},min{w[j],r-len+1<=j<=r})

    若都在预先处理中先求得两个区间的最小值

    则每次查询的复杂度都是O(1)

    ---

     

    对len做一个限制:只能为2的幂

    在预处理中求出所有mi[b][t] : 以b为起点,长为2^t的区间的最小值.

    则求解min(min{w[i],l<=i<=l+len-1},min{w[j],r-len+1<=j<=r})

    就变成min(mi[l][t],mi[r-2^t+1][r]),其中t可以由此得出,以保证两段区间可以覆盖待求区间:

    t=ln(r-l+1)/ln(2)

    ---

     

    可以看到mi[b][t]=min(mi[b][t-1],mi[b+2^(t-1)-1][t-1])

    特别地对于所有mi[i][0],其值都是w[i];

    由此自底向上推出所有的mi[b][t]

    mi大小为n*logn,预处理时间复杂度为O(nlogn),查询时间复杂度为O(1)

    -----------------------------------------------------代码------------------------------------------------------

    在POJ上测试, 反应良好~

    不知道怎么样把函数指针指向任意类型的<操作符, 只能总是提供一个"小于"函数

    查询指定区间的最小值.

    ----------------------------------以下是模板-------------------------------------

    template < class Type>
    class rmq_st{
    private:
          Type* body;   
          int** mi;      
          int size;     
          int len;     

          int dint(double a){       
              int buf=a;   
              if(buf>a){
                  --buf;
              }
              return buf;
          }

          int mlen(int l,int r){
              double buf=log((double)(r-l+1))/log((double)2);  
              return dint(buf)
          }   
          bool (*less)(Type& t1,Type& t2);

    public:


         //构造函数 : (待求数组,大小,小于函数)      
          rmq_st(Type* con,int s,bool (*lessthan)(Type& t1,Type& t2));
               
          ~rmq_st();//解构
         
          Type get_body(int p);//返回指定索引的元素

          int query_index(int l,int r);//返回指定区间最小值的元素索引

          Type query(int l,int r);//返回指定区间的最小元素
    };

    template < class Type>
    rmq_st< Type>::rmq_st(Type* con,int s,bool (*lessthan)(Type& t1,Type& t2)){
          less=lessthan;
          body=con;
          size=s;
          len=mlen(0,s-1)+1;
          mi=new int*[size];
          int i,j;
          for(i=0;i< size;++i){
              mi[i]=new int[len];
          }
          int bound;  
          int a,b;    
          for(i=0;i< size;++i){   
              mi[i][0]=i;
          }
          for(i=1;i< len;++i){     
              bound=n-(1<< i)+1;      
              for(j=0;j< bound;++j){      
                  a=mi[j][i-1];       
                  b=mi[j+(1<< (i-1))][i-1];    
                  mi[j][i]=less(body[a],body[b])?a:b;
              }
          }
    }

    template < class Type>
    rmq_st< Type>::~rmq_st(){
          int i;
          for(i=0;i< size;++i){
              delete[] mi[i];
          }    
          delete[] mi;
    }

    template < class Type>
    Type rmq_st< Type>::get_body(int p){
          return body[p];
    }

    template < class Type>
    int rmq_st< Type>::query_index(int l,int r){
          int length=mlen(l,r);        
          int a=mi[l][length];
          int b=mi[r-(1<< length)+1][length];
          return less(body[a],body[b])?a:b;
    }

    template < class Type>
    Type rmq_st< Type>::query(int l,int r){
          int length=mlen(l,r);
          int a=mi[l][length];
          int b=mi[r-(1<< length)+1][length];
          return less(body[a],body[b])?body[a]:body[b];
    }

    /*----------------Example : POJ 3264    Memory:7708K   Time:3230MS-----------------*/

    int cow[50001];
    int n,q;

    bool cmpmin(int& t1,int& t2){
          return t1< t2;
    }

    bool cmpmax(int& t1,int& t2){
          return t1>t2;
    }

    int main()
    {
    //    freopen("1.in","r",stdin);
          scanf("%d %d",&n,&q);
          int i;    
          for(i=0;i< n;++i){
              scanf("%d",&cow[i]);
          }
          rmq_st< int> minst(cow,n,cmpmin);
          rmq_st< int> maxst(cow,n,cmpmax);
          int a,b;
          for(i=0;i< q;++i){
              scanf("%d %d",&a,&b);
              --a;
              --b;
              printf("%d\n",maxst.query(a,b)-minst.query(a,b));
          }      
          return 0;
    }

  • 相关阅读:
    【matlab】学习笔记 2脚本编写
    【matlab】学习笔记 1 入门简单操作
    【matlab】学习笔记 3 函数编写
    MySQL学习笔记
    数据库连接-----MySQL -> JDBC
    leetcode——Mysql数据库查询题目
    不同单词个数统计
    初始化二维数组
    JS基本变量类型和对象杂谈
    LeetCode Clone Graph
  • 原文地址:https://www.cnblogs.com/ACAC/p/1743142.html
Copyright © 2011-2022 走看看