[LuoguP1888]滑动窗口(单调队列)

链接:https://www.luogu.com.cn/problem/P1886
description: 有一个长为 n 的序列 a,以及一个大小为 k 的窗口。现在这个窗口从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值。
solution: 以最小值为例, 维护一个双端队列:
对原数组:1,3,-1,-3,5,3,6,7
我们将双端队列做成单调不减的,队首即为当前位的最小值.
将arr的每个数据依次试探入队, q非空时,若 arr[i]<=arr[q.back()] 则可以淘汰q.back()这一位.因为q.back()比arr[i]早入队且数值不占优, 不可能成为此后的最小值.
若队首已经滞留k轮, 模拟窗口右移, 不得不强制弹出.
实现借助STL的 deque

code:

#include<cstdio>
#include<deque>
int main() {
	std::deque<int> maxq, minq;
	int n, k;
	scanf("%d%d", &n, &k);
	const int* arr = new int[n];
	int* max = new int[n], * min = new int[n];
	for (int i = 0; i < n; i++)scanf("%d", arr + i);
	for (int i = 0; i < n; i++) {
		while (!minq.empty() && arr[i] <= arr[minq.back()])minq.pop_back();
		minq.push_back(i);
		if (i - minq.front()+1>k)minq.pop_front();
		min[i] =arr[minq.front()];
	        while (!maxq.empty() && arr[i] >= arr[maxq.back()])maxq.pop_back();
		maxq.push_back(i);
		if (i - maxq.front()+1>k)maxq.pop_front();
		max[i] =arr[maxq.front()];
	}
	for (int i = k - 1; i < n; i++)printf("%d ", min[i]);
	printf("\n");
	for (int i = k - 1; i < n; i++)printf("%d ", max[i]);
}
posted @ 2021-01-29 17:39  _dwt  阅读(63)  评论(0)    收藏  举报