题目:

给一个长度为N的数组,一个长为K的滑动窗体从最左端移至最右端,你只能看到窗口中的K个数,每次窗体向右移动一位。你的任务是找出窗体在各个位置时的最大值和最小值。


做法:

单调队列的经典例题。
最大值最小值分开处理。
处理最大值时,从左到右遍历维护一个数值从大到小的单调队列。具体操作就是每加入一个数从队尾扫到队头发现有比它小的数则覆盖掉(相当于剪掉尾巴)。队头先pop掉不在窗口中的数值,然后在队头查询以该位置为窗口右端点的答案。复杂度O(n)
最小值同理。


代码:

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false), cin.tie(0)
#define debug(a) cout << #a ": " << a << endl
using namespace std;
typedef long long ll;
const int N = 1e6 + 7;
int n, m, a[N];
int q[N<<1], top, tail;
int mx[N], mn[N];
int main(void){
    IOS;
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) cin >> a[i];
    top = tail = 0;
    for (int i = 1; i <= n; ++i){
        while (top < tail && a[q[tail-1]] <= a[i]) tail--;
        q[tail++] = i;
        while (i > m && q[top] <= i-m) top++;
        mx[i] = a[q[top]];
    }
    top = tail = 0;
    for (int i = 1; i <= n; ++i){
        while (top < tail && a[q[tail-1]] >= a[i]) tail--;
        q[tail++] = i;
        while (i > m && q[top] <= i-m) top++;
        mn[i] = a[q[top]];
    }
    for (int i = m; i <= n; ++i) cout << mn[i] << ' '; cout << endl;
    for (int i = m; i <= n; ++i) cout << mx[i] << ' '; cout << endl;
    return 0;
}