Balanced Lineup——RMQ

本文介绍了一种使用ST表进行区间查询优化的方法,特别适用于寻找区间内最大值和最小值的问题。通过预处理建立ST表,可以实现O(nlgn)的时间复杂度构建表,并在O(1)时间内完成区间查询,优于线段树和树状数组在不需要修改操作的情况下的表现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门 POJ - 3264

描述

For the daily milking, Farmer John’s N cows (1 ≤ N ≤ 50,000) always line up in the same order. One day Farmer John decides to organize a game of Ultimate Frisbee with some of the cows. To keep things simple, he will take a contiguous range of cows from the milking lineup to play the game. However, for all the cows to have fun they should not differ too much in height.
Farmer John has made a list of Q (1 ≤ Q ≤ 200,000) potential groups of cows and their heights (1 ≤ height ≤ 1,000,000). For each group, he wants your help to determine the difference in height between the shortest and the tallest cow in the group.

输入

Line 1: Two space-separated integers, N and Q.
Lines 2.. N+1: Line i+1 contains a single integer that is the height of cow i
Lines N+2.. N+ Q+1: Two integers A and B (1 ≤ A ≤ B ≤ N), representing the range of cows from A to B inclusive.

输出

Lines 1.. Q: Each line contains a single integer that is a response to a reply and indicates the difference in height between the tallest and shortest cow in the range.

样例

  • 输入
    6 3
    1
    7
    3
    4
    2
    5
    1 5
    4 6
    2 2
  • 输出
    6
    3
    0

思路

  • 题意:给n个数和m次询问,每次询问给l和r,求区间[l,r]中最大值和最小值的差值。
  • st[i][j]表示区间[i,i+2^j-1]内的最值。
  • 以最大值为例,st[i][j]=max(st[i][j-1],st[i+(1<<(j-1))][j-1])
  • 询问区间[l,r]时,取区间[l,l+(1<<k)][r-(1<<k)+1][r],其中k=log(r-l+1.0)/log(2.0),这样两个区间必有交集,则两个区间的最大值的最大值就一定是[l,r]的最大值。
  • st表构造O(nlgn),查找O(1)。当需要多次查找区间最值,不需要进行修改操作时,st表比线段树、树状数组更好用。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include<iostream>
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<cmath>
#define INIT(a,b) memset(a,b,sizeof(a))
#define LL long long int
using namespace std;
const int MAX=0x7fffffff;
const int MIN=-0x7fffffff;
const int INF=0x3f3f3f3f;
const int Mod=1e9+7;
const int maxn=50007;
int st1[maxn][20],st2[maxn][20];
int n,m,l,r;
void Rmq(){
for(int j=1;(1<<j)<=n;j++) //外层j,稍加推导即可理解
for(int i=1;i+(1<<j)-1<=n;i++){ //st[i][j]包含区间 [i,i+2^j-1]
st1[i][j]=max(st1[i][j-1],st1[i+(1<<(j-1))][j-1]);
st2[i][j]=min(st2[i][j-1],st2[i+(1<<(j-1))][j-1]);
}

}
int Find(int l,int r){
int k=log(double(r-l+1))/log(2.0);
int ans1=max(st1[l][k],st1[r-(1<<k)+1][k]);
int ans2=min(st2[l][k],st2[r-(1<<k)+1][k]);
return abs(ans1-ans2);
}
int main(){
//freopen("1.in","r",stdin);
//freopen("1.out","w",stdout);
scanf("%d%d",&n,&m);
INIT(st2,INF);INIT(st1,0);
for(int i=1;i<=n;i++){
scanf("%d",&st1[i][0]);
st2[i][0]=st1[i][0];
}
Rmq();
while(m--){
scanf("%d%d",&l,&r);
printf("%d\n",Find(l,r));
}
return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值