P1886 滑动窗口 /【模板】单调队列
题目描述
有一个长为 n 的序列 a,以及一个大小为 k 的窗口。现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值。
例如,对于序列 [1,3,−1,−3,5,3,6,7] 以及 k=3,有如下过程:
窗口位置[1 3 -1] -3 5 3 6 7 1 [3 -1 -3] 5 3 6 7 1 3 [-1 -3 5] 3 6 7 1 3 -1 [-3 5 3] 6 7 1 3 -1 -3 [5 3 6] 7 1 3 -1 -3 5 [3 6 7]最小值−1−3−3−333最大值335567
输入格式
输入一共有两行,第一行有两个正整数 n,k。 第二行 n 个整数,表示序列 a
输出格式
输出共两行,第一行为每次窗口滑动的最小值
第二行为每次窗口滑动的最大值
输入输出样例
输入 #1
8 3 1 3 -1 -3 5 3 6 7
输出 #1
-1 -3 -3 -3 3 3 3 3 5 5 6 7
说明/提示
【数据范围】
对于 50% 的数据,1≤n≤105;
对于 100% 的数据,1≤k≤n≤106,ai∈[−231,231)。
思路:
单调队列的模板,由于我们需要求出每次窗口中的最大和最小值,所以我们需要维护两个单调队列
对于每一个单调队列,元素是从小到大放进去的,所以我们每次都需要检查目前处于队首的元素是否在当前窗口内。
第二,针对特定的队列,我们以维护最大值的队列来说。每次当来到一个位置时,我们需要考虑当前元素的值是否比队尾元素大,如果更大,则需要将队尾元素删掉,直到队尾元素比它大,因为此时这个位置的元素所在位置肯定比队尾元素更靠后,也就是说有效窗口更靠后,那么如果此时这个窗口中最大元素都不是队尾,那么后面的窗口就更不可能是它了,所以直接删掉。
#include<bits/stdc++.h>
using namespace std;typedef struct Group{int x,y,tim;
// bool operator<(Group g) const{
// if(x!=g.x) return x<g.x;
// else return y<g.y;
// }
}G;
typedef long long ll;
const int mod = 1e6+7;
int n,m;
int r,c;
int dx[4] = {0,0,1,-1};
int dy[4] = {1,-1,0,0};int main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin>>n>>m;vector<int> nums(n+1,0);for(int i=1; i<=n; i++) cin>>nums[i];vector<int> minn;vector<int> maxn;deque<int> qMax;deque<int> qMin;for(int i=1; i<=n; i++){while(!qMax.empty()&&qMax.front()<=i-m) qMax.pop_front();while(!qMin.empty()&&qMin.front()<=i-m) qMin.pop_front();while(!qMax.empty()&&nums[i]>=nums[qMax.back()]) qMax.pop_back();while(!qMin.empty()&&nums[i]<=nums[qMin.back()]) qMin.pop_back();qMax.push_back(i);qMin.push_back(i);if(i>=m){minn.push_back(qMin.front());maxn.push_back(qMax.front());}}for(int i=0; i<minn.size(); i++){if(i==0) cout<<nums[minn[i]];else cout<<" "<<nums[minn[i]];}cout<<endl;for(int i=0; i<maxn.size(); i++){if(i==0) cout<<nums[maxn[i]];else cout<<" "<<nums[maxn[i]];}return 0;
}