[POJ 3264] Balanced Lineup (ST表)

链接

POJ 3264


题意

给出N个整数,Q个询问,每个询问给出一个区间[l, r],要求得出区间内整数的最大值与最小值之差。


思路

典型的一个RMQ问题,之前是用线段树做的,这次用st表试一下。
st表是专门用来处理区间最值查询的数据结构,它跟线段树不同,线段树是在O(n)内构建,单次查询/更新为O(log(n))的复杂度,但是线段树能处理更复杂的问题,比如更新整个区间(lazy标记)和对区间做计数统计。
st表对长度为n的序列,可在O(n*log(n))内构建完毕,之后对任意区间[l, r]查询复杂度均为O(1),但是st表的功能没有那么强大,只能解决区间最值的查询,对于“区间内有多少个元素满足条件”这样的问题就无法解决。
另一个类似的结构是树状数组,是一种“精简版”的线段树,可用来做单点更新和区间查询,但是更复杂的“区间更新”问题就无法解决。


关于st表
/*
 * st表
 * st[i][j]表示元素arr[i]开始,长度为2^j区间内的最值
 * st[i][0]为arr[i],st[i][j] = max(st[i][j-1], st[i - (1 << j-1)][j-1])
 * 求区间[l, r]内最值:
 * log2[i]代表i的对数向下取整
 * 对于长度len而言,显然2^log2[len]严格大于len的一半
 * 令k = log2[r - l + 1],则最值为max(st[l][k], st[r - (1<<k) + 1][k])
 */

#define maxn (55000)
int log2[maxn], st[maxn][32];
void st_prepare(int n, int *arr)
{
    log2[1] = 0;
    for(int i = 2; i <= n; i++)
    {
        log2[i] = log2[i - 1];
        if((1 << log2[i] + 1) == i)
            log2[i]++;
    }

    for(int i = n; i >= 1; i--)
    {
        st[i][0] = arr[i];
        for(int j = 1; i + (1 << j) - 1 <= n; j++)
        {
            st[i][j] = max(st[i][j - 1], st[i + (1 << j - 1)][j - 1]);
        }
    }
}
int st_query(int l, int r)
{
    int len = r - l + 1, k = log2[len];
    return max(st[l][k], st[r - (1 << k) + 1][k]);
}

代码
#include <cstdio>
#include <iostream>
#include <vector>
using namespace std;
#define maxn (55000)
int log2[maxn], mx[maxn][32], mn[maxn][32];
void st_prepare(int n, int *arr)
{
    log2[1] = 0;
    for(int i = 2; i <= n; i++)
    {
        log2[i] = log2[i - 1];
        if((1 << log2[i] + 1) == i)
            log2[i]++;
    }

    for(int i = n; i >= 1; i--)
    {
        mx[i][0] = mn[i][0] = arr[i];
        for(int j = 1; i + (1 << j) - 1 <= n; j++)
        {
            mx[i][j] = max(mx[i][j - 1], mx[i + (1 << j - 1)][j - 1]);
            mn[i][j] = min(mn[i][j - 1], mn[i + (1 << j - 1)][j - 1]);
        }
    }
}
int st_query(int l, int r)
{
    int len = r - l + 1, k = log2[len];
    return max(mx[l][k], mx[r - (1 << k) + 1][k]) - min(mn[l][k], mn[r - (1 << k) + 1][k]);
}

int cow[maxn];
int main()
{
    int N, Q, L, R;
    cin >> N >> Q;
    for(int i = 1; i <= N; i++)
        scanf("%d", &cow[i]);
    st_prepare(N, cow);
    while(Q--)
    {
        scanf("%d%d", &L, &R);
        printf("%d\n", st_query(L, R));
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值