poj 3264 Balanced Lineup(两遍sparse-table算法的rmq问题)

来源:互联网 发布:我知女人心小说阅读 编辑:程序博客网 时间:2024/05/22 17:19
刚搞掉了ping pong那个BIT 照着训练指南乘胜追击学的RMQ问题 这个题我貌似早就见过 一直都不会。刚才有了BIT的思想学了一下 sparse-table算法
还算比较简单吧。
先说说这个算法 就是给出序列 和查询 q i j问你i和j之间的最小值是多少
这个暴力的话要n方 肯定是不行的。但是st算法预处理的时间是nlogn 查询时间基本是o(1)的
我们用一个二维数组d记录
d[i][j]表示的是 以i为起点长度是 2的j次方的这 一段 序列中的最小值。用一点dp的思想 递推得到整个数组
d[i][j]= min(d(i,j-1),d(i+1<<(j-1),j-1))相当于把这个序列分成两段了。然后找最小值
d数组的元素个数不超过nlogn
因为d[i][j]的计算是要用到前一列 也就是j-1这一列。。。所以按照列来求。。
书上给的我觉得有一点问题。。。一个循环里的问题
初始化代码
void RMQ_init()
{
    for(int i=1;i<=n;++i)
        d[i][0]=arr[i];
    for(int j=1;(1<<(j))<=n;++j)
    {
        for(int i=1;i+(1<<(j-1))<=n;++i)
        {
            d[i][j]=min(d[i][j-1],d[i+(1<<(j-1))][j-1]);
        }
    }
}

查询也比较简单 就是令 k 是满足 (1<<k) <(r-l+1) 最大的整数
那么 d[l][k] 和 d[r-1<<(k)+1][k] 就覆盖了l到r这个区间 
中间重叠元素也不影响 因为是取最小值么。。

查询代码如下

int RMQ_query(int l,int r)
{
    while((1<<(k+1))<=(r-l+1))
    k++;
    return min(d[l][k],d[r-(1<<k)+1][k]);
}

这样就可以了。。
再来说这道题吧。。
输入n 和 q 然后是n个数  然后 q 个询问 每个询问 l r
给出ans是l 和 r之间最大值和最小值的差。
其实就是RMQ问题再预处理一个 区间最大值么。。

敲完 吃了饭 wa了一次 然后AC了。。
wa是因为d数组开小了
我直接输出log2(maxn) 是15 忽略掉了一个问题
d的size应该是16 因为从1开始 而且0也用了。

#include<iostream>
#include<cstdio>
#include<cstring>

#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))

using namespace std;
const int maxn=50005;
int n,q;
int arr[maxn];

int dmin[maxn][16];
int dmax[maxn][16];

void RMQ_init()
{
    int i,j;
    for(i=1;i<=n;++i)
    {
        dmin[i][0]=arr[i];
        dmax[i][0]=arr[i];
    }
    for(j=1;(1<<j)<=n;++j)
    {
        for(i=1;(i+(1<<(j-1)))<=n;++i)
        {
            dmin[i][j]=min(dmin[i][j-1],dmin[i+(1<<(j-1))][j-1]);
            dmax[i][j]=max(dmax[i][j-1],dmax[i+(1<<(j-1))][j-1]);
        }
    }
}

int RMQ_Query(int l,int r)
{
    int k=0;
    while((1<<(k+1)<=(r-l+1)))k++;
    int Min=min(dmin[l][k],dmin[r-(1<<(k))+1][k]);
    int Max=max(dmax[l][k],dmax[r-(1<<(k))+1][k]);
    return Max-Min;
}



int main()
{

    int i,l,r,Min,Max;
    while(scanf("%d %d",&n,&q)!=EOF)
    {
        for(i=1;i<=n;++i)
        scanf("%d",&arr[i]);
        RMQ_init();
        while(q--)
        {
            scanf("%d %d",&l,&r);
            printf("%d\n",RMQ_Query(l,r));
        }
    }
    return 0;
}

原创粉丝点击