滑动窗口单调队列

it2026-04-02  6

有一个长为 n 的序列 a,以及一个大小为 k 的窗口。现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值。

要构造单调递增以及单调递减队列,分别按以下思路进行: 递 增 队 列 ( 输 出 最 小 值 ) { 若 待 插 入 队 列 的 元 素 小 于 队 尾 元 素 , 则 弹 出 队 尾 元 素 直 到 待 插 入 元 素 大 于 等 于 队 尾 元 素 为 止 若 待 插 入 元 素 大 于 等 于 队 尾 元 素 , 则 直 接 插 入 该 元 素 递增队列(输出最小值)\left\{\begin{array}{l} 若待插入队列的元素小于队尾元素,则弹出队尾元素直到待插入元素大于等于队尾元素为止 \\ \\若待插入元素大于等于队尾元素,则直接插入该元素 \end{array}\right. 递 减 队 列 ( 输 出 最 大 值 ) { 若 待 插 入 队 列 的 元 素 大 于 队 尾 元 素 , 则 弹 出 队 尾 元 素 直 到 待 插 入 元 素 小 于 等 于 队 尾 元 素 为 止 若 待 插 入 元 素 小 于 等 于 队 尾 元 素 , 则 直 接 插 入 该 元 素 递减队列(输出最大值)\left\{\begin{array}{l} 若待插入队列的元素大于队尾元素,则弹出队尾元素直到待插入元素小于等于队尾元素为止 \\ \\若待插入元素小于等于队尾元素,则直接插入该元素 \end{array}\right.

#include <cstdio> #include <cstring> const int maxn = 1000005; struct monque { int n, k, head, tail; int a[maxn], q[maxn], p[maxn]; void read() { scanf("%d%d", &n, &k); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); } void monque_min() { head = 1; tail = 0; for (int i = 1; i <= n; i++) { while (head <= tail && q[tail] >= a[i]) tail--; q[++tail] = a[i]; p[tail] = i; while (p[head] <= i - k) head++; if (i >= k) printf("%d ", q[head]); } printf("\n"); } void monque_max() { head = 1; tail = 0; for (int i = 1; i <= n; i++) { while (head <= tail && q[tail] <= a[i]) tail--; q[++tail] = a[i]; p[tail] = i; while (p[head] <= i - k) head++; if (i >= k) printf("%d ", q[head]); } printf("\n"); } } Monque; int main() { Monque.read(); Monque.monque_min(); Monque.monque_max(); return 0; }

参考 https://www.luogu.com.cn/blog/hankeke/solution-p1886

最新回复(0)