题面
【题目描述】
农夫 JohnJohnJohn 的N(1<=N<=50,000)N(1 <= N <= 50,000)N(1<=N<=50,000)头牛总是按同一序列排队. 有一天,JohnJohnJohn 决定让一些牛们玩一场飞盘比赛. 他准备找一群在队列中位置连续的牛来进行比赛. 但是为了避免水平悬殊,牛的身高不应该相差太大. JohnJohnJohn准备了Q(1<=Q<=180,000)Q (1 <= Q <= 180,000)Q(1<=Q<=180,000)个可能的牛的选择和所有牛的身高 (1<=1 <=1<=身高<=1,000,000<= 1,000,000<=1,000,000). 他想知道每一组里面最高和最低的牛的身高差别.
【输入】
第111行:N,QN,QN,Q
第222到N+1N+1N+1行:每头牛的身高
第N+2N+2N+2到N+Q+1N+Q+1N+Q+1行:两个整数AAA和BBB,表示从AAA到BBB的所有牛。(1<=A<=B<=N1<=A<=B<=N1<=A<=B<=N)
【输出】
输出每行一个数,为最大数与最小数的差
【样例输入】
6 3
1
7
3
4
2
5
1 5
4 6
2 2
【样例输出】
6
3
0
算法分析
ST表模板题目。
a数组表示N头牛的身高。
f[i][j]f[i][j]f[i][j]:表示序列a[i]a[i]a[i]开始,连续2j2^j2j个数的最大值。
s[i][j]s[i][j]s[i][j]:表示序列a[i]a[i]a[i]开始,连续2j2^j2j个数的最小值。
状态转移方程:
f[i][j]=max(f[i][j−1],f[i+2j−1][j−1])f[i][j]=max(f[i][j-1],f[i+2^{j-1}][j-1])f[i][j]=max(f[i][j−1],f[i+2j−1][j−1])
s[i][j]=minx(s[i][j−1],s[i+2j−1][j−1])s[i][j]=minx(s[i][j-1],s[i+2^{j-1}][j-1])s[i][j]=minx(s[i][j−1],s[i+2j−1][j−1])
询问区间a[x]a[x]a[x] ~ a[y]a[y]a[y]最大、小值?
找到一个kkk,使得[x,x+2k−1]∪[y−2k+1,y]=[x,y][x , x+2^k-1 ]∪[ y-2^k+1 , y]=[x,y][x,x+2k−1]∪[y−2k+1,y]=[x,y]
需要满足:2k<=y−x+12^k<=y-x+12k<=y−x+1
取 k=log2(y−x+1)k=log_2(y-x+1)k=log2(y−x+1)
区间[x,y][x,y][x,y]最大值=max(f[x][k],f[y−2k−1][k])max( f[x][k], f[y-2^k-1][k] )max(f[x][k],f[y−2k−1][k])
区间[x,y][x,y][x,y]最小值=min(s[x][k],s[y−2k−1][k])min( s[x][k], s[y-2^k-1][k] )min(s[x][k],s[y−2k−1][k])
参考程序
#include<bits/stdc++.h>
#define N 100010
using namespace std;
int f[N][25],s[N][25];
int n,m,x,y;
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&f[i][0]);
s[i][0]=f[i][0]; //初始化
}
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
{
f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
s[i][j]=min(s[i][j-1],s[i+(1<<(j-1))][j-1]);
}
while(m--)
{
scanf("%d%d",&x,&y);
int k=log(y-x+1)/log(2);
printf("%d\n",max(f[x][k],f[y-(1<<k)+1][k])-min(s[x][k],s[y-(1<<k)+1][k]));
}
return 0;
}

本文详细解析了一道经典的ST表模板题目,通过农夫John的牛群身高问题,阐述了如何利用ST表进行区间最大值和最小值的快速查询。文章深入介绍了状态转移方程、查询算法,并提供了完整的参考程序。
1234

被折叠的 条评论
为什么被折叠?



