RMQ算法题目

pku 3264 http://poj.org/problem?id=3264

题意:

给定n个奶牛的高度,求区间[s,e]中最高与最低高度的差值。

rmq模板题目:

求出最高最低然后求差。

注意这里f[i][j]表示从j开始的2^i次方个数的最值。

View Code
#include <cstdio>

#include <cstring>

#include <iostream>

#include <cmath>

#define maxn 50007

#define N 22

using namespace std;



int fMin[N][maxn],fMax[N][maxn];

int pow2[N],a[maxn];



void init_rmq(int len)

{

    int i,j;

    for (i = 0; i < N; ++i) pow2[i] = 1<<i;



    for (i = 1; i <= len; ++i)

    fMin[0][i] = fMax[0][i] = a[i];



    for (i = 1; pow2[i] <= len; ++i)//pow2[i]表示长度一定小于总长度

    {

        for (j = 1; j + pow2[i - 1] <= len; ++j)//j + pow2[i - 1]表示右边的起点一定要小于最右边的坐标

        {

            fMax[i][j] = max(fMax[i - 1][j],fMax[i - 1][j + pow2[i - 1]]);

            fMin[i][j] = min(fMin[i - 1][j],fMin[i - 1][j + pow2[i - 1]]);

        }

    }

}



int rmq(int s,int e)

{

    int k = log(1.0*(e -s + 1))/log(2.0);

    int Max = max(fMax[k][s],fMax[k][e - pow2[k] +1]);

    int Min = min(fMin[k][s],fMin[k][e - pow2[k] +1]);

    return Max - Min;

}

int main()

{

    //freopen("d.txt","r",stdin);

    int n,q,i;

    int s,e;

    scanf("%d%d",&n,&q);

    for (i = 1; i <= n; ++i) scanf("%d",&a[i]);



    init_rmq(n);

    while (q--)

    {

        scanf("%d%d",&s,&e);

        printf("%d\n",rmq(s,e));

    }

    return 0;

}

 

 pku Frequent values http://poj.org/problem?id=3368

题意:

给定长度为n的不降序列,求询问区间[s,e]内出现频率最高的频率;

思路:

本题可用线段树的区间合并来做:http://www.cnblogs.com/E-star/archive/2012/07/26/2609475.html

rmq做法,首先将其离散化相同的点映射到一个点上,并记录该点能够达到的最左端点最有端点;

分三种情况讨论[s,e]

hash[i]位i离散化后对应的新序号,R[hash[i]]表示i离散化后的点能够到达的最右端,L[hash[i]]表示i离散化后的点能够到达的最左端,

1:如果s与e对应的离散化后的点为同一点则频率为 e - s + 1;(1,1,1,1)

2:如果s与e所对应的离散化后的点相差1则频率为 Li = R[hash[l]] - l + 1;   Ri = r - L[hash[r]] + 1; max(Li,Ri); (1 1 3 3)

3:如果s与e所对应的离散化后的点相差大于1则频率为

Li = R[hash[l]] - l + 1;
Ri = r - L[hash[r]] + 1;
Li = max(Li,Ri);
Ri = rmq(hash[l] + 1,hash[r] - 1);
max(Li,Ri);

View Code
#include <cstdio>

#include <cstring>

#include <iostream>

#include <cmath>

#define maxn 100007

using namespace std;



int hash[maxn],L[maxn],R[maxn];

int a[maxn],f[maxn][22],pow2[22];



void init_rmq(int len)

{

    int i,j;

    for (i = 0; i < 22; ++i) pow2[i] = 1<<i;



    for (j = 1; pow2[j] <= len; ++j)

    {

        for (i = 1; i + pow2[j] <= len; ++i)

        f[i][j] = max(f[i][j - 1],f[i + pow2[j - 1]][j - 1]);

    }

}

int rmq(int s,int e)

{

    int k = log(1.0*(e - s + 1))/log(2.0);

    return max(f[s][k],f[e - pow2[k] + 1][k]);

}



void solve(int l,int r)

{

    int Li,Ri;

    if (hash[l] == hash[r])

    {

        printf("%d\n",r - l + 1);

    }

    else if (hash[l] + 1 == hash[r])

    {

        Li = R[hash[l]] - l + 1;

        Ri = r - L[hash[r]] + 1;

        printf("%d\n",max(Li,Ri));

    }

    else

    {

        Li = R[hash[l]] - l + 1;

        Ri = r - L[hash[r]] + 1;

        Li = max(Li,Ri);

        Ri = rmq(hash[l] + 1,hash[r] - 1);

        printf("%d\n",max(Li,Ri));

    }

}

int main()

{

    //freopen("d.txt","r",stdin);

    int n,q,i;

    while (~scanf("%d",&n))

    {

        if (!n) break;

        scanf("%d",&q);

        for (i = 1; i <= n; ++i) scanf("%d",&a[i]);

        hash[1] = 1;

        L[1] = 1;

        R[1] = 1;

        int cnt = 1;

        for (i = 2; i <= n; ++i)

        {

            if (a[i] == a[i - 1])

            {

                hash[i] = hash[i - 1];

                R[hash[i]] = i;

            }

            else

            {

                f[cnt][0] = R[cnt] - L[cnt] + 1;//直接对f初始化了。

                hash[i] = ++cnt;

                L[cnt] = i;

                R[cnt] = i;

            }

        }

        f[cnt][0] = R[cnt] - L[cnt] + 1;

        init_rmq(cnt);

        int s,e;

        while (q--)

        {

            scanf("%d%d",&s,&e);

            solve(s,e);

        }

    }

    return 0;

}

 

你可能感兴趣的:(算法)