RMQ(Range Minimum/Maximum Query(ST表实现)(附带例题)

ST表预处理复杂度O(nlogn),查询为ST表为O(1),st表的主体是一个二维数组st[i][j],采用的是dp(动态规划)的思想,i表示从位置i开始长度为2^j次幂的一个区间(即往右移动2^j-1个单位)。求一个区间的MAX以及MIN。

先看预处理的代码:这边写的是一个MIN,同理找区间最大即就是MAX

状态转移方程:st[i][j] = min (st [i] [j - 1],st [i + 2^(j - 1)] [j - 1]):即i+2^(j-1)----i+2^(j-1)+2^(j-1)比较

int a[1000];//原始输入数组
int st[1000][20];//st表

void init(int n)
{
      int i,j;
    for (i=0;i<n;i++)
        st[i][0] = a[i];//将第一位赋值

    for (j=1;(1<<j)<=n;j++)
    {

        for (i=0;i+(1<<j)<=n;i++)

            st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);

    }
}

接下来就是查询函数,作为查询一段区间的MAX或者MIN;

int solvemin(int l,int r)//查询l---r的区间MIN
{
	int k=log2(r-l+1);
	return min(stmin[l][k],stmin[r-(1<<k)+1][k]);
}

不妨反向推导一下,(int)  k=log2(r-l+1)由此可知 2^k<=(r-l+1)

并且2^k+l的肯定超过了(l+r)/2;

所以l到r的最小值可以表示为min(从l往后2^t的最小值,从r往前2^t的最小值) 

带一道例题:

题目来源:http://poj.org/problem?id=3264 POJ 3264

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
int a[50010];
int stmax[50010][20];
int stmin[50010][20];
void init(int n)
{
	int i,j,k;
    for(i=1;i<=n;i++) 
	stmax[i][0]=stmin[i][0]=a[i];
    int t=log2(n)+1;
    for(int j=1;j<t;j++)
	{
        for(int i=1;i<=n-(1<<j)+1;i++)
		{
            stmax[i][j]=max(stmax[i][j-1],stmax[i+(1<<(j-1))][j-1]);
            stmin[i][j]=min(stmin[i][j-1],stmin[i+(1<<(j-1))][j-1]);
        }
    }
}
int solvemax(int l,int r)
{
    int k=log2(r-l+1);
    return max(stmax[l][k],stmax[r-(1<<k)+1][k]);
}
int solvemin(int l,int r)
{
	int k=log2(r-l+1);
	return min(stmin[l][k],stmin[r-(1<<k)+1][k]);
}
int main()
{
    int n,q,i,j;
    scanf("%d %d",&n,&q);
        for (i=1;i<=n;i++)
        scanf("%d",&a[i]);
        init(n);
        while(q--)
        {
            int l,r;
            scanf("%d %d",&l,&r);
            printf("%d\n",solvemax(l,r)-solvemin(l,r));
        }
        return 0;
}
发布了56 篇原创文章 · 获赞 17 · 访问量 2341

猜你喜欢

转载自blog.csdn.net/weixin_43958964/article/details/99471436