先定义单调队列: 顾名思义是单调递增或单调递减的队列,队首为队列的最大值或最小值。
可以进行的操作:
1.队首出队
2.队尾进队出队
题意: 告诉你一组数组的长度,以及一个固定的区间M。例如 A[ 1.......N] ,固定区间长度为M,问自i=1时起区间A[i.....i+M-1] 中的最大值依次是多少
思路:区间最值问题可以用线段树来解决,但是线段树的访问存在对一个区间范围的重复计算,改用单调队列,每个元素只进队出队一次
对于操作1:当队尾元素在数组中的下标-队首元素在数组中的下标+1>固定区间长度时,队首出队
对于操作2 :由于我们是依次考虑每个元素,以单调队列递增为例,当当前元素的值<=队尾元素时,队尾出队直到队尾元素>当前元素,然后将该元素进队,此时该队列仍然保持单调性,然后执行操作1
#include<stdio.h>
int QueueMin[1111111];
int QueueMax[1111111];
int AnsMin[1111111];
int AnsMax[1111111];
int Front1,Rear1,Front2,Rear2;
int Val[1111111];
int N,M;
int main(){
int i,j,k;
while(~scanf("%d %d",&N,&M)){
Front1=Rear1=Front2=Rear2=0;
for(i=1;i<=N;i++){
scanf("%d",&Val[i]);
}
for(i=1;i<=N;i++){
while(Front2<Rear2&&Val[i]<=Val[QueueMin[Rear2-1]]){
Rear2--;
}
QueueMin[Rear2++]=i;
while(Front2<Rear2&&i-QueueMin[Front2]+1>M){
Front2++;
}
AnsMin[i]=Val[QueueMin[Front2]];
}
for(i=1;i<=N;i++){
while(Front1<Rear1&&Val[i]>=Val[QueueMax[Rear1-1]]){
Rear1--;
}
QueueMax[Rear1++]=i;
while(Front1<Rear1&&i-QueueMax[Front1]+1>M){
Front1++;
}
AnsMax[i]=Val[QueueMax[Front1]];
}
for(i=M;i<=N;i++)
printf("%d ",AnsMin[i]);
printf("\n");
for(i=M;i<=N;i++)
printf("%d ",AnsMax[i]);
printf("\n");
}
return 0;
}