RMQ问题ST算法与模板

原文链接:http://www.cnblogs.com/ACAC/archive/2010/05/24/1743142.html 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;
}

转载于:https://www.cnblogs.com/ACAC/archive/2010/05/24/1743142.html

上一篇:[bzoj3790]神奇项链


下一篇:python学习笔记---十二