随笔-68  评论-10  文章-0  trackbacks-0
RMQ(Range Minimum/Maximum Query)问题是求区间最值问题,用ST算法,可以做到O(nlogn)的预处理,O(1)地回答每个询问。
以求最大值为例,设f[i,j]表示以i为起点,长度为2^j这个区间中的最大值,即[i,i+2^j-1]这个区间内的最大值,那么在询问[a,b]区间的最大值时答案就是max(f[a,k], f[b-2^k+1,k]),其中k是满足2^k<=b-a的最大的k,即k=ln(b-a+1)/ln(2);另外,这两个区间必须覆盖[a,b].
f的求法可以用动态规划,f[i,j]=max(f[i,j-1],f[i+2^(j-1),j-1]).

题目链接:http://acm.pku.edu.cn/JudgeOnline/problem?id=3264
#include<iostream>
#include
<cmath>
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b) 
using namespace std;
int n,q,a,b;
int h[50005];
int maxn[50005][16];
int minn[50005][16];
void st_init()
{
     
for(int i=1;i<=n;i++
     maxn[i][
0]=minn[i][0]=h[i];
     
int m=int(log(double(n))/log(2.0));
     
for(int i=1;i<=m;i++)
     
for(int j=1;j<=n;j++)
     
{
          maxn[j][i]
=maxn[j][i-1];
          
if(j+(1<<(i-1))<=n) 
          maxn[j][i]
=max(maxn[j][i],maxn[j+(1<<(i-1))][i-1]);
     }

     
     
for(int i=1;i<=m;i++)
     
for(int j=1;j<=n;j++)
     
{
          minn[j][i]
=minn[j][i-1];
          
if(j+(1<<(i-1))<=n)
          minn[j][i]
=min(minn[j][i],minn[j+(1<<(i-1))][i-1]);
     }
    
}

int st_search(int l,int r)
{
    
int m=int(log(double(r-l+1))/log(2.0));
    
int mx=max(maxn[l][m],maxn[r-(1<<m)+1][m]);
    
int mn=min(minn[l][m],minn[r-(1<<m)+1][m]);
    
return mx-mn;
}

int main()
{
    scanf(
"%d%d",&n,&q);
    
for(int i=1;i<=n;i++)
    scanf(
"%d",&h[i]);
    st_init();
    
for(int i=1;i<=q;i++)
    
{
        scanf(
"%d%d",&a,&b);
        printf(
"%d\n",st_search(a,b));
    }

    
//system("pause");
    return 0;
}

posted on 2010-08-28 13:29 wuxu 阅读(201) 评论(0)  编辑 收藏 引用 所属分类: 动态规划

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理