POJ 3264--Balanced Lineup(RMQ问题)

来源:互联网 发布:php unpack 字符串 编辑:程序博客网 时间:2024/05/22 17:50

题意:给定一数组a[i],输入任意范围内的最大最小值之差。

题解:典型的RMQ(range min/max query)问题,对于此种问题,有三种较好的方法。

  • 线段树:易知对于区间问题,可以使用区间树较好地解决。在建树时可以使用递归分治的方法,将[a,b]分成两段(a == b则直接返回对应数组值),在分治函数返回时,只需要比较左右两个子区间的最大最小值就能求出[a,b]之间的最大最小值。
  • ST算法:动态规划的方法,以最小值为例
  1. 设dp[i][j] = min{a[k],i <= k <= i+2^j-1},即dp[i][j]为从dp[i]开始到第2^j个数为止的最小值,显然dp[i][0] = a[i]。
  2. 当j >= 1时,我们可以把上述规模为2^j的区间分成两部分,即[i,i+2^(j-1)-1]以及[i+2^(j-1),i+2^j-1],于是得到动态转移方程:dp[i][j] = min{dp[i][j-1],dp[i+2^(j-1)][j-1]}。
  3. 当查询区间[a,b]的最小值时我们同样可以把此区间分成两部分,假设分成2^n的两部分(可能有重叠),即有两区间[a,a+2^n-1]以及[b-2^n+1,b],易知要满足条件a + 2^n - 1 >= b - 2^n +1,得n >= log2(b-a+2)-1
  • 第三种方法较为复杂,可参考http://community.topcoder.com/tc?module=Static&d1=tutorials&d2=lowestCommonAncestor#Range_Minimum_Query_%28RMQ%29

线段树:
#include<iostream>#include<cstdio>#include<cstring>#include<cmath>using namespace std;#define maxN 50005#define maxM 20int height[maxN];class node{public:    int minHeight,maxHeight;};node tree[maxN*3];class solve{private:    int N,Q;    int A,B;    int minHeight,maxHeight;public:    solve(int n,int q):N(n),Q(q)    {        processIn();        buildTree(1,1,N);        while(Q--)        {            scanf("%d%d",&A,&B);            minHeight = 0X7FFFFFFF;            maxHeight = 0;            Search(1,1,N,A,B);            printf("%d\n",maxHeight-minHeight);        }    }    void processIn();    void buildTree(int nodeNo,unsigned short a,unsigned short b);    int Search(int nodeNo,unsigned short A,unsigned short B,unsigned short a,unsigned short b);};int solve::Search(int nodeNo,unsigned short A,unsigned short B,unsigned short a,unsigned short b){    if(A == a&&B == b)    {        minHeight = min(minHeight,tree[nodeNo].minHeight);        maxHeight = max(maxHeight,tree[nodeNo].maxHeight);        return 0;    }    int left = nodeNo<<1;    int right = left|1;    unsigned short mid = (A+B)>>1;    if(a > mid)    {        Search(right,mid+1,B,a,b);    }    else if(b <= mid)    {        Search(left,A,mid,a,b);    }    else    {        Search(left,A,mid,a,mid);        Search(right,mid+1,B,mid+1,b);    }    return 0;}void solve::buildTree(int nodeNo,unsigned short a,unsigned short b){    if(a == b)    {        tree[nodeNo].minHeight = tree[nodeNo].maxHeight = height[a];        return ;    }    int left = nodeNo<<1;    int right = left|1;    unsigned short mid = (a+b)>>1;    buildTree(left,a,mid);    buildTree(right,mid+1,b);    tree[nodeNo].minHeight = min(tree[left].minHeight,tree[right].minHeight);   //取左右子树中最小值的较小值    tree[nodeNo].maxHeight = max(tree[left].maxHeight,tree[right].maxHeight);   //取左右子树中最大值的较大值    return ;}void solve::processIn(){    for(int i = 1;i <= N;i++)    {        scanf("%d",height+i);    }    return ;}int main(){    int n,q;    while(~scanf("%d%d",&n,&q))    {        solve poj_3264(n,q);    }    return 0;}

ST:
#include<iostream>#include<cstdio>#include<cstring>#include<cmath>using namespace std;#define maxN 50005#define maxM 20int height[maxN];int dp_min[maxN][maxM];int dp_max[maxN][maxM];class solve{private:    int N,Q;    int A,B;    int max_j;public:    solve(int n,int q):N(n),Q(q)    {        processIn();        RMQ_Init();        while(Q--)        {            A = strIn();            B = strIn();            printf("%d\n",RMQ(A,B));        }    }    void processIn();    void RMQ_Init();    int RMQ(int a,int b);    int strIn();};int solve::strIn(){    int num = 0;    char c;    while((c = getchar())&&c != '\n'&&c != ' '&&c > 0)    {        num *= 10;        num += c-'0';    }    return num;}int solve::RMQ(int a,int b){    if(a == b)        return 0;    int k = ceil(log((double)(b-a+2))/log(2.0))-1;    int tmpMin = min(dp_min[a][k],dp_min[b-(1<<k)+1][k]);    int tmpMax = max(dp_max[a][k],dp_max[b-(1<<k)+1][k]);    return tmpMax-tmpMin;}void solve::RMQ_Init(){    int i,j;    max_j = floor(log((double)(N+1))/log(2.0));    for(i = 1;i <= N;i++)    {        dp_min[i][0] = dp_max[i][0] = height[i];    }    for(j = 1;j <= max_j;j++)    {        for(i = 1;i+(1<<(j-1)) <= N;i++)        {            dp_min[i][j] = min(dp_min[i][j-1],dp_min[i+(1<<(j-1))][j-1]);            dp_max[i][j] = max(dp_max[i][j-1],dp_max[i+(1<<(j-1))][j-1]);        }    }    return ;}void solve::processIn(){    getchar();    for(int i = 1;i <= N;i++)    {        height[i] = strIn();    }    return ;}int main(){    int n,q;    while(~scanf("%d%d",&n,&q))    {        solve poj_3264(n,q);    }    return 0;}


0 0
原创粉丝点击