队列CSP-J

目录

💡 核心思想

队列是一种先进先出(FIFO)的数据结构,从队尾入队、从队首出队。在竞赛中,队列是 BFS 的核心数据结构。进阶应用包括单调队列(滑动窗口最值)和双端队列。

单调队列是 CSP-S 的常考知识点。它可以在 $O(n)$ 时间内求出滑动窗口的最大/最小值。核心思想是维护一个双端队列,保持队列中的元素对应的值单调,当窗口滑动时移除过期的元素。

🎯 直觉理解

队列就像排队买票——先来的人先买到(先进先出)。单调队列就像一个VIP通道——如果你后面来了一个比你强的人,你就可以走了(因为在你之前他永远是更优选择)。

📝 算法流程

  1. 基本操作:push, pop, front, back
  2. 单调队列:维护单调性 + 窗口范围
  3. 双端队列 deque:两端都可以进出

$$\text{单调队列:每个元素最多入队出队各一次,总计} O(n)$$

📊 复杂度分析

指标复杂度
时间$O(n)$(单调队列)
空间$O(n)$

💻 参考实现(C++)

C++ (C++17)
#include <bits/stdc++.h>
using namespace std;
// 单调队列:滑动窗口最小值
int main() {
    int n, k; cin >> n >> k;
    vector<int> a(n);
    for (auto& x : a) cin >> x;
    deque<int> dq; // 存下标
    for (int i = 0; i < n; i++) {
        while (!dq.empty() && a[dq.back()] >= a[i]) dq.pop_back();
        dq.push_back(i);
        if (dq.front() <= i - k) dq.pop_front();
        if (i >= k - 1) cout << a[dq.front()] << " ";
    }
    return 0;
}

⚠️ 常见坑点

单调队列弹出条件要注意是 > 还是 >=

窗口过期判断要用下标差

deque 的 pop_front/pop_back 不能在空队列上调用

用数组模拟队列时注意循环队列的取模

📚 相关题目

题目来源难度备注
P1886 滑动窗口洛谷CSP-S单调队列模板
P2032 扫描洛谷CSP-S单调队列