poj 3264 Balanced Lineup (RMQ))

来源:互联网 发布:绣春刀2剧情解析知乎 编辑:程序博客网 时间:2024/06/07 06:45
Balanced Lineup
Time Limit:5000MS     Memory Limit:65536KB     64bit IO Format:%lld & %llu
Submit Status

Description

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.. NQ+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.


根据题意,要求得某一个区间内的最大值和最小值之差,数组长度为50000,查询次数为20W,可以看出用暴力肯定要超时,这时候要求用效率更高的算法来解决问题,这个题用到了RMQ,nlogn的预处理,o(1)的查询,效率是能够满足本题的。

RMQ算法也称为ST表,分为两部分,首先是预处理,然后是查询。

在预处理部分,我们假设dp[I][j],是以i为起点,2的j次方为长度的中的最小值,首先判断边界,先看j,数组长度为n,所以2的j次方应该小于等于n,当j=0时,该区间的就只有a[i]一个数字,所以最小值就a[i]本身,然后再来看i,i从0开始,每次算区间的时候,区间末位为:i+1<<j-1,既是这个区间末位应该在总数组长度n以内,边界已经判断完,我们再来看dp的转移方程,我们把一个区间dp[i][j]分为两块,一块是以i为起点,2的(j-1)次方为区间长度,另外一块以(i+(1<<j-1))为起点,以i+1<<j-1为终点,可以看出,这两个区间是相交的,所以总区间的最小值就等于这两个分区间的最小值中的最小值,即是 dp[i][j]=min(dp[i]j-1],dp[i+1<<j-1][j-1]),相当于把一个区间分为长度相等的两个区间,把这个区间的长度进行二分操作达到提高效率,然后我们在来看dp是一个二维数组,i是数组的长度,而j则是以i为起点的2的j次方数据长度,所以j的范围为0-log2n,j的范围为log比较小,所以数组不算大,再来看转移的时候的循环,在两重循环中,j在外层,i在内层,以为dp方程的每次求的数都是根据j-1来确定的,所以以j来分层。

查询部分,输入一个区间,可以先把这个区间的长度进行区分,找到一个k值,使得2的k次方<=区间长度,这样就把这个区间尽量的分开成足够长的两个子区间,然后再通过dp转移方程求得区间的最小值:ansmin=min(dpmin[a][k],dpmin[b-(1<<k)+1][k]);

总结:时间和空间的优化都在预处理过程中,先把结果打成一个ST表,便于每次查询都能达到o(1)的复杂度,在预处理过程中,一层一层的把区间长度不断扩大一直到数组的长度,通过每一次的比较区间的最值而不是比较单个数据来提高效率。最后注意区间的范围和数据下标的处理。

#include<stdio.h>#include<algorithm>#include<string.h>using namespace std;int dpmin[50050][20];int dpmax[50050][20];int n,q;int main(){    int a[50005];    while(scanf("%d%d",&n,&q)!=EOF)    {        for(int i=0;i<n;i++)            scanf("%d",&a[i]);        for(int i=0;i<n;i++)            dpmax[i][0]=dpmin[i][0]=a[i];        for(int j=1;(1<<j)<=n;j++)        {            for(int i=0;i+(1<<j)-1<n;i++)            {                dpmin[i][j]=min(dpmin[i][j-1],dpmin[i+(1<<(j-1))][j-1]);                dpmax[i][j]=max(dpmax[i][j-1],dpmax[i+(1<<(j-1))][j-1]);            }        }        while(q--)        {            int a,b;            scanf("%d%d",&a,&b);            a--;            b--;            int len=b-a+1;            int k=0;            int temp=1;            while(temp<=len)            {                k++;                temp*=2;            }            k--;            int ansmax=max(dpmax[a][k],dpmax[b-(1<<k)+1][k]);            int ansmin=min(dpmin[a][k],dpmin[b-(1<<k)+1][k]);            printf("%d\n",ansmax-ansmin);        }    }return 0;}


0 0