poj 3264 Balanced Lineup ( ST算法(dp))

11 篇文章 0 订阅
1 篇文章 0 订阅

题意:

          给出N个数,Q个询问。

           每个询问求区间[L,R]中最大值与最小值之差。

做法:

          ST算法,本质上是一种dp。

          假设用二位数组来保存最大值的信息,其中max[i][j]表示从第i个数开始(每行0号元素不用,即i! = 0),长度为2^j的区间,即[i, i + 2^j-1]。

          则max[i + 2 ^ j][j]表示从第(i + 2 ^ j)个数开始,长度为2 ^j的区间,即[i + 2 ^ j,(i +2 ^ j)+ 2 ^ j-1]。

  很容易发现, [i, i + 2^j-1]和[i + 2 ^ j,i + 2 ^ j+2^j-1]这两个区间刚好组成了区间[i ,i + 2 ^ j+2^j-1]。即[i,i+2 ^ (j+1)-1]。

  而[i,i+2 ^ (j+1)-1]表示的就是从第i个数开始,长度为2^(j+1)的区间。

  于是有max[i][j+1]=MAX(max[i][j],max[i+2^j][j]

  根据这种倍增的思想,可求出所有长度为2^j(0<=j<log2(n))的区间上的最大值。

  对应每个询问[L,R],设len=R-L,x=log2(len) 

  则区间[L,R]可分成[L,L+2^x-1]和[R-2^x+1,R],两个区间中间可能会重叠,但绝不会有间隔。

  于是[L,R]上的最大值即为MAX(max[L][x],max[R-2^x+1][x])

   

  最小值的做法同法,然后相减即为答案。

 

 

#include <cstdio>
#include <cmath>
#include <iostream>
using namespace std;
const int MAXN = 50005, MAXM = 22;
int maxh[MAXN][MAXM], minh[MAXN][MAXM];

int main() {
    int n,q,l,r,x;
    while(~scanf("%d%d",&n,&q)) {

        for(int i = 0; i < n; i++) {
            scanf("%d",&x);
            maxh[i][0] = minh[i][0] = x;
        }

        for(int i = 1; (1 << i ) < n; i++)
            for(int j = 0; j + (1 << i) - 1 < n; j++) {
                maxh[j][i] = max(maxh[j][i - 1],maxh[j + (1 << (i - 1))][i - 1]);
                minh[j][i] = min(minh[j][i - 1],minh[j + (1 << (i - 1))][i - 1]);
            }

        while(q--) {
            scanf("%d%d",&l,&r);
            l--;
            r--;
            x = (int) log2(r - l + 1.0) ;
            printf("%d\n",max(maxh[l][x],maxh[r - (1 << x) + 1][x])-min(minh[l][x],minh[r - (1 << x) + 1][x]));
        }

    }
    return 0;
}

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值