zoukankan      html  css  js  c++  java
  • RMQ谈:Range Minimum/Maximum Query 区间最小/大值查询 ST优化

    RMQ(Range Minimum/Maximum Query)  对于长度为n的数列A,回答若干询问RMQ(A, i, j) (i,j<=n),返回数列A中下标在i,j里的最小(大)值

    给出m次查询   最常想到的是遍历  复杂度为O(nm).

    改进方法:

    (1)、ST(sparse table)算法 

    基于这样的一个事实:一大块区间求最大/小值,可以分成两个小块分别求出最大/小值(分治法的思想),然后再将 求出的两个极值 比较 ,求出最后最值。

                                                       例如:                                    

    a)、预处理

    分配一个d[n][log2n]大小的数据区:

    d[i][k] 记录数列A[i,  i+2k-1]之间的最值(包括两端点),时间复杂度O(nlog2n)

    在做预处理时有一个动态规划的思想:d[i][k] = min/max( d[i][ k-1 ],d[  i+2k-1  ][ k-1 ] ).

    b)、处理查询

    k=[log2(j-i+1)];

    RMQ(i,j) = min/max(d[i][k],d[j-2k+1][k]);

    这里有个小技巧是: d[j-2k+1][k]下标j开始往前数2k个数  与      d[i][k]从下标i开始往后数2k个数一定包括了A[i,j]这个区间(个数小于2k+1

    时间复杂度O(1)

    #include <iostream>
    #include <stdlib.h>
    #include <math.h>
    
    using namespace std;
    
    void swap(int *i,int *j);
    int query(int i,int j);
    int **table;
    
    void RMQ(int arr[],int n)
    {
      //cout<<"RMQ"<<endl;
      int w = log2(n);
      for(int i=1;i<=n;i++)table[i][0]=arr[i];//cout<<table[i][0]<<endl;
      int tmp;//cout<<w<<endl;
      for(int i=1;i<=w;i++)
      {
         tmp=1;tmp=tmp<<(i-1);
         for(int j=1;j+tmp<=n;j++)        
         {
            if(i==4&&j==1)cout<<*(*(table+j)+i-1)<<" "<<*(*(table+j+tmp)+i-1)<<endl;
            if(*(*(table+j)+i-1) < *(*(table+j+tmp)+i-1))
                *(*(table+j)+i) = *(*(table+j)+i-1);
            else
                *(*(table+j)+i) = *(*(table+j+tmp)+i-1);
         }
      }
    }
    
    int main()
    {
      int n;
      cin>>n;
      int *arr = (int *)malloc(sizeof(int)*(n+1));
      int *p = arr;
      for(int i=1;i<=n;i++)
      {
         *(p+i) = rand()%17 + 1;
         cout<<*(p+i)<<" ";
      }cout<<endl;
      
      table = (int **)malloc(sizeof(int*)*(n+1));
      for(int i=1;i<=n;i++)*(table+i) = (int *)malloc(sizeof(int)*(log2(n)+1));
    
      RMQ(arr,n);
      
      for(int j=1,k=1;j<=n;j++)
      {
         int step = 0;cout<<j<<":  ";
         for(int i=0;j+(1<<i)-1<=n;i++)        
         {        
            printf("%5d ",*(*(table+j)+i));
         }
         cout<<endl;
      }
      
      int m;
      cin>>m;
      while(m--)
      {
        int i,j;
        cin>>i>>j;
        if(i>j)swap(i,j); 
        if(i<1)i=1;
        if(j>n)j=n;
        cout<<"result: "<<query(i,j)<<endl;         
      }
      
      for(int i=1;i<=100;i++)
      {
         cout<<*(p+i)<<" "<<endl;
      }
      system("pause");
      return 0;    
    }
    
    void swap(int *i,int *j)
    {
      int tmp = *i;     
      *i = *j;
      *j = tmp;
    }
    
    int query(int i,int j)
    {
        int dif = j-i+1;
        int log_dif = log2(dif);
        int tmp = 1;
        //cout<<i<<" "<<j<<" "<<log_dif<<endl;
        if(*(*(table+i)+log_dif) < *(*(table+j-(tmp<<log_dif)+1)+log_dif))
           return *(*(table+i)+log_dif);
        else
           return *(*(table+j-(tmp<<log_dif)+1)+log_dif);
    }
  • 相关阅读:
    Maven------使用maven新建web项目出现问题 项目名称出现红色交叉
    Strut2------获取界面返回的session,application,parameter
    js之可迭代对象
    js字符串
    js之strict模式
    js系列之js简介
    python私有成员
    python之偏函数
    python之装饰器
    python之匿名函数
  • 原文地址:https://www.cnblogs.com/lwer/p/2833306.html
Copyright © 2011-2022 走看看