学习来源↓
题解 P1886 【滑动窗口】
性质:学习来源
- 队列中的元素其对应在原来的列表中的顺序必须是单调递增的 - 说的是 for(1~n)
- 队列中元素的大小必须是单调递*(增/减/甚至是自定义也可以)
单调队列与普通队列不一样的地方就在于:单调队列既可以从队首出队,也可以从队尾出队
单调队列板子
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int a[N];
int n, m, k;
namespace Monotonous_queue { //单调队列板子
int q[N];
int h = 1, t = 0;//首 尾
//需要的就那么几个东西
int p[N];//编号
void queryMax() {
h = 1;
t = 0; // 每次从队尾加入新的值
for (int i = 1; i <= n; ++i) {
//a[i]为当前处理的值
while (h <= t && q[t] <= a[i]) t--;
//剔除非最大值的值 此时剩下的就是比a[i]更大的值
q[++t] = a[i]; //把新的值加入进来
p[t] = i;
while (p[h] + k <= i) h++;//缩小范围
if (i >= k) {
cout << q[h] << ' ';//每次窗口间的最大值
}
}
cout << endl;
}
void queryMin() {
h = 1;
t = 0;
for (int i = 1; i <= n; ++i) {
//a[i]为当前处理的值
while (h <= t && q[t] >= a[i]) t--;
q[++t] = a[i];
p[t] = i;
while (p[h] + k <= i) h++;
if (i >= k) { //区间个数要等于k 那么肯定是处理到第k个开始才会有值输出
cout << q[h] << ' ';
}
}
cout << endl;
}
}
using namespace Monotonous_queue;
int main() {
ios::sync_with_stdio(0);
cin >> n >> k;//n个数 窗口大小为k
for (int i = 1; i <= n; ++i) {
cin >> a[i];
}
queryMin();
queryMax();
return 0;
}
二维单调队列板子
#include <bits/stdc++.h>
using namespace std;
namespace MonotonousQueue2 {//二维单调队列
const int N = 1005;// 当N=5000时 危 · 抠细节
typedef long long ll;
int head1, tail1, head2, tail2;
int qMax[N][N], qMin[N][N];
int a[N][N];
struct node {
int v;//val
int id;
} q1[N], q2[N];//q1 维护纵向 q2 维护横向
void addMax(int v, int id) {//维护队列最大值
while (head1 < tail1 && q1[tail1 - 1].v <= v) tail1--;
q1[tail1++] = {v, id};
}
int getMaxNum(int id) {
while (head1 < tail1 && q1[head1].id < id) head1++;
return q1[head1].v;
}
void addMin(int v, int id) {//维护队列最小值
while (head2 < tail2 && q2[tail2 - 1].v >= v) tail2--;
q2[tail2++] = {v, id};
}
int getMinNum(int id) {
while (head2 < tail2 && q2[head2].id < id) head2++;
return q2[head2].v;
}
//在 n*m 的网格里 找 r*c的矩阵 里的最大值和最小值 的差值
void MQ2(int n, int m, int r, int c) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
scanf("%d", &a[i][j]);
}
}
for (int j = 0; j < m; j++) {
head1 = tail1 = head2 = tail2 = 0;
for (int i = 0; i < r - 1; i++) {
addMax(a[i][j], i);
addMin(a[i][j], i);
}
for (int i = r - 1; i < n; i++) {
addMax(a[i][j], i);
// 这里qMax[i][j]表示第j列, max( matrix[ i->(i+r) ][j] )中的最大值
qMax[i - r + 1][j] = getMaxNum(i - r + 1);
addMin(a[i][j], i);
qMin[i - r + 1][j] = getMinNum(i - r + 1);
}
}
for (int i = 0; i < n - r + 1; i++) {
head1 = tail1 = head2 = tail2 = 0;
for (int j = 0; j < c - 1; j++) {
addMax(qMax[i][j], j);
addMin(qMin[i][j], j);
}
for (int j = c - 1; j < m; j++) {
addMax(qMax[i][j], j);
qMax[i][j - c + 1] = getMaxNum(j - c + 1);
addMin(qMin[i][j], j);
qMin[i][j - c + 1] = getMinNum(j - c + 1);
}
}
int res = qMax[0][0] - qMin[0][0];
for (int i = 0; i < n - r + 1; i++) {
for (int j = 0; j < m - c + 1; j++) {
res = min(res, qMax[i][j] - qMin[i][j]);
}
}
printf("%d\n", res);
}
}
using namespace MonotonousQueue2;
int main() {
ios::sync_with_stdio(false);
int a, b, n;
while (~scanf("%d%d%d", &a, &b, &n))
MQ2(a, b, n, n);
return 0;
}