题面
【题目描述】
农夫
J
o
h
n
John
John 的
N
(
1
<
=
N
<
=
50
,
000
)
N(1 <= N <= 50,000)
N(1<=N<=50,000)头牛总是按同一序列排队. 有一天,
J
o
h
n
John
John 决定让一些牛们玩一场飞盘比赛. 他准备找一群在队列中位置连续的牛来进行比赛. 但是为了避免水平悬殊,牛的身高不应该相差太大.
J
o
h
n
John
John准备了
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). 他想知道每一组里面最高和最低的牛的身高差别.
【输入】
第
1
1
1行:
N
,
Q
N,Q
N,Q
第
2
2
2到
N
+
1
N+1
N+1行:每头牛的身高
第
N
+
2
N+2
N+2到
N
+
Q
+
1
N+Q+1
N+Q+1行:两个整数
A
A
A和
B
B
B,表示从
A
A
A到
B
B
B的所有牛。(
1
<
=
A
<
=
B
<
=
N
1<=A<=B<=N
1<=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]开始,连续
2
j
2^j
2j个数的最大值。
s
[
i
]
[
j
]
s[i][j]
s[i][j]:表示序列
a
[
i
]
a[i]
a[i]开始,连续
2
j
2^j
2j个数的最小值。
状态转移方程:
f
[
i
]
[
j
]
=
m
a
x
(
f
[
i
]
[
j
−
1
]
,
f
[
i
+
2
j
−
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
]
=
m
i
n
x
(
s
[
i
]
[
j
−
1
]
,
s
[
i
+
2
j
−
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]最大、小值?
找到一个
k
k
k,使得
[
x
,
x
+
2
k
−
1
]
∪
[
y
−
2
k
+
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]
需要满足:
2
k
<
=
y
−
x
+
1
2^k<=y-x+1
2k<=y−x+1
取
k
=
l
o
g
2
(
y
−
x
+
1
)
k=log_2(y-x+1)
k=log2(y−x+1)
区间
[
x
,
y
]
[x,y]
[x,y]最大值=
m
a
x
(
f
[
x
]
[
k
]
,
f
[
y
−
2
k
−
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]最小值=
m
i
n
(
s
[
x
]
[
k
]
,
s
[
y
−
2
k
−
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;
}