原题链接:
https://ac.nowcoder.com/acm/problem/50528
题目大意:
给一个长度为的数组,一个长为
的滑动窗体从最左端移至最右端,你只能看到窗口中的
个数,每次窗体向右移动一位,如下图:
你的任务是找出窗体在各个位置时的最大值和最小值。
解题思路:
爆内存,线段树只过90%,所以要用单调队列。
本题我们模拟一个单调队列,队列中只存后面可能有用的数据,以取区间最大值为例,如果在一个长度为的区间
且
,那么知道可以删除掉
,这样不会影响区间最大值。所以我们在向队列中增加新元素的时候,我们比较队尾与新元素的大小,如果队尾元素小于新元素,那么队尾元素在后续不会出现了,也就是说被新元素覆盖了,那么就可以删除它,直到无法在覆盖。所以,按照这种消法队首元素一直都是最大的,所以每一次输出就输出队首元素。当然要记得队首元素超出要求的区间时,要删掉该元素。所以单调队列中存取的可以是对应元素在数组的坐标。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i,a,b) for(i=a;i<=b;i++)
#define debug(a) cout<<#a<<":"<<a<<endl;
const int INF=1e9+7;
const int N=1e6+7;
const int mod=1e9+7;
int maxn,minn;
int T,n,m;
int arr[N];
int du[N];
int main(){
int l,r;
cin>>n>>m;
for(int i=1;i<=n;i++){
scanf("%d",arr+i);
}
du[1]=1;
l=1,r=2;
if(m==1){
cout<<du[l]<<" ";
}
for(int i=2;i<=n;i++){
if(i-du[l]==m){
l++;
}
while(r!=l&&arr[i]<=arr[du[r-1]]){
r--;
}
du[r]=i;
r++;
if(i>=m)
cout<<arr[du[l]]<<" ";
}
cout<<endl;
l=1,r=2;
if(m==1){
cout<<du[l]<<" ";
}
for(int i=2;i<=n;i++){
if(i-du[l]==m){
l++;
}
while(r!=l&&arr[i]>=arr[du[r-1]]){
r--;
}
du[r]=i;
r++;
if(i>=m)
cout<<arr[du[l]]<<" ";
}
cout<<endl;
return 0;
} 
京公网安备 11010502036488号