UVA 11235 RMQ(范围最小值(最大值)问题):Sprase Table算法

算法入门经典训练指南198页。

范围最小值问题(Range Minimum Query,RMQ).实践中最常用的是Sparse Table 算法,预处理时间是O(nlogn),查询只需要O(1),而且常数很小。

注意到整个数组是非降序的,所有相等元素会聚集到一起。这样可以把整个数组进行游程编码。比如-1,1,1,2,,2,2,4可以编码成(-1,1)(1,2),(2,3),(4,1),其中(a,b)表示有b个连续的a.


#include <iostream>
#include <map>
#include <deque>
#include <vector>
#include <queue>
#include <stack>
#include <string>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <map>
#include <set>
using namespace std;
const int m=100005;
int a[m],l[m],r[m],num[m],d[m][30];
void RMQ_init(const vector<int>&A)
{
    int i,j,n=A.size();
    for(i=0; i<n; i++)
        d[i][0]=A[i];
    for(j=1; (1<<j)<=n; j++)
        for(i=0; i+(1<<j)-1<n; i++)
            d[i][j]=max(d[i][j-1],d[i+(1<<(j-1))][j-1]);
}
int RMQ(int L,int R)
{
    int k=0;
    while((1<<(k+1))<=R-L+1) k++;
    return max(d[L][k],d[R-(1<<k)+1][k]);
}
int main()
{
    int n,q,i,j;
    while(scanf("%d",&n),n)
    {
        scanf("%d",&q);
        for(i=0; i<n; i++)
            scanf("%d",&a[i]);
        a[n]=a[n-1]+1;
        int start=-1;
        vector<int>count;
        for(i=0; i<=n; i++)
            if(a[i]>a[i-1])
            {
                if(i!=0)
                {
                    count.push_back(i-start);
                    for(j=start; j<i; j++)
                    {
                        num[j]=count.size()-1;
                        l[j]=start;
                        r[j]=i-1;
                    }
                    start=i;
                }
            }
        RMQ_init(count);
        while(q--)
        {
            int L,R,sum;
            scanf("%d%d",&L,&R);
            L--;R--;
            if(num[L]==num[R]) sum=R-L+1;
            else
            {
                sum=max(r[L]-L+1,R-l[R]+1);
                if(num[L]+1<=num[R]-1)
                    sum=max(sum,RMQ(num[L]+1,num[R]-1));
            }
            printf("%d\n",sum);
        }
    }
    return 0;
}


你可能感兴趣的:(UVA 11235 RMQ(范围最小值(最大值)问题):Sprase Table算法)