[RMQ之稀疏表(ST表)讲解及例题][POJ 3264]Balanced Lineup

讲解:
介绍:
稀疏表(Sparse Table, ST 表)与线段树、树状数组一样,也是常用来处理序列上的区间询问问题的。但 ST 表只能处理区间最值,即RMQ(Range Minimum Query)问题,它的空间需求也比前两者要大,是 O(nlogn) 级别的。ST 表需要 O(nlogn) 的时间预处理,但能 O(1) 回答单次区间最值的询问。不过并不支持修改操作。因此它适用于无修改且询问次数较多的 RMQ 问题。
算法流程:
1、稀疏表其实在维护一个个长度为 2x 的区间,我们定义一个数组f[i][j],代表区间 [i,i+2j1] 的最值(下以最小值为例),其长度是 2j (这也是为什么要减一)。
2、区间 [i,i+2j1] 可以分成两部分 [i,i+2j11] + [i+2j1,i+2j1] ,转化成数组表示有: f[i][j]=min(f[i][j1]f[i+2j1][j1]) (j=0时,f[i][j]=a[i])。
而j的大小是 logn 的,所以预处理是 nlogn 的。
PS:求log有函数,但是速度较慢,用 ST表时n 的大小不会太大,最多只有 106 级别,因此可以利用位运算预处理出n 以内所有数的log 大小。
3、询问[x,y]时,可以求出 log2(yx+1) (由上的PS只可以O(1)得到,且相当于log后取整了的),假设结果为i,这样就可以用两个长度为 2i 的小区间覆盖询问的大区间。因为[x,y]长度不一定刚刚好是2的多少次方,所以这两个小区间有交集,但对于最值来说并没有影响,这也就是 ST表只适用于最值这类问题的原因。例图:
这里写图片描述
PS:此图来源于 Gao Wenyuan 的PDF。
例题:
题目描述:
题目链接POJ 3264 Balanced Lineup

For the daily milking, Farmer John’s N cows (1 ≤ N ≤ 50,000) always line up in the same order. One day Farmer John decides to organize a game of Ultimate Frisbee with some of the cows. To keep things simple, he will take a contiguous range of cows from the milking lineup to play the game. However, for all the cows to have fun they should not differ too much in height.

Farmer John has made a list of Q (1 ≤ Q ≤ 200,000) potential groups of cows and their heights (1 ≤ height ≤ 1,000,000). For each group, he wants your help to determine the difference in height between the shortest and the tallest cow in the group.

Input
Line 1: Two space-separated integers, N and Q.
Lines 2..N+1: Line i+1 contains a single integer that is the height of cow i
Lines N+2..N+Q+1: Two integers A and B (1 ≤ A ≤ B ≤ N), representing the range of cows from A to B inclusive.
Output
Lines 1..Q: Each line contains a single integer that is a response to a reply and indicates the difference in height between the tallest and shortest cow in the range.
Sample Input

6 3
1
7
3
4
2
5
1 5
4 6
2 2

Sample Output

6
3
0

题目大意:
给定一个长度为 n 的序列 ai ,q 次询问,每次询问一个区间 [l,r] 内最大值与最小值的差值是多少, n50000 , q2105
题目分析:
ST表模板题。
附代码:

#include<iostream>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cstdio>
#include<ctime>
#include<cmath>
#include<cctype>
#include<iomanip>
#include<algorithm>
using namespace std;

const int maxn=50010;
const int logn=15;
int n,m,a[maxn],minn[maxn][logn+1],maxx[maxn][logn+1];
int logg[maxn],l,r,minans,maxans,ans,k;

int main()
{
    //freopen("lx.in","r",stdin);

    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    logg[0]=-1;
    for(int i=1;i<=n;i++)
    {
        minn[i][0]=maxx[i][0]=a[i];
        logg[i]=logg[i>>1]+1;//预处理1~n对应的log
    }
    for(int j=1;j<=logn;j++)
        for(int i=1;i+(1<<j)-1<=n;i++)
        {
            minn[i][j]=min(minn[i][j-1],minn[i+(1<<(j-1))][j-1]);
            maxx[i][j]=max(maxx[i][j-1],maxx[i+(1<<(j-1))][j-1]);           
        }
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&l,&r);
        k=logg[r-l+1];
        maxans=max(maxx[l][k],maxx[r-(1<<k)+1][k]);
        minans=min(minn[l][k],minn[r-(1<<k)+1][k]);
        ans=maxans-minans;
        printf("%d\n",ans);
    }

    return 0;   
}
发布了99 篇原创文章 · 获赞 8 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qianguch/article/details/78228351
今日推荐