Tommy Chen home

单调队列

17 Aug 2025

1. 简介

2. 实现

模板:洛谷 P1886

对于长度为 n 的序列,有一个长度为 k 的窗口。窗口从左到右每次滑动一个单位,求每次滑动后窗口内的最大值和最小值。


input
8  3
1  3  -1  -3  5  3  6  7


output
min -1 -3 -3 -3  3  3
max  3  3  5  5  6  7

思路:


for(int i = 1; i <= n; i++) { // 求最大值
		while(!q.empty() && q.front() < i - k + 1)
			q.pop_front();
		while(!q.empty() && a[q.back()] < a[i])
			q.pop_back();
		q.push_back(i);
  	maxi[i] = a[q.front()];
}


for(int i = 1; i <= n; i++) { // 求最小值
		while(!q.empty() && q.front() < i - k + 1)
			q.pop_front();
		while(!q.empty() && a[q.back()] > a[i])
			q.pop_back();
		q.push_back(i);
		mini[i] = a[q.front()];
}

3. 变形

示例 1:洛谷 P1714——求长度不超过 m 的最大子段和。

题意:给定序列 p1、…、pn,找出一个子段 [l, r],满足 r − l + 1 ≤ m,并使 Σi = lr pi 最大。

与模板不同的是,本题要求区间和,而非直接求最值,因此需要使用前缀和。

对序列求前缀和后,得到数组 sum[]。区间 [l, r] 的和可表示为 sum[r] - sum[l-1]。

思路:

示例 2:洛谷 P2216(二维)

题意:

给定一个由 a×b 个整数组成的矩阵,找出一个 n×n 的正方形区域,使其中最大值与最小值之差最小。


input
a = 5, b = 4, n = 2
1   2   5   6
0   17  16  0
16  17  2   1
2   10  2   1
1   2   2   2


output
1

思路:

Total visits to this site: times