[单调队列]P2216 [HAOI2007] 理想的正方形 题解
其实就是建立 \(a\) 个单调队列,然后同时维护一个长度为 \(n\) 的区间最大值和最小值,最后再对这 \(a\) 个单调队列所维护的区间最大值和最小值做一个长度为 \(n\) 的单调队列,也是维护一个长度为 \(n\) 的区间最大值和最小值。
相当于第一把把矩阵压缩成一个序列,第二把对序列做单调队列。
细节也没什么问题,整型就可以存下。代码看着长,其实都是单调队列的板子罢了。
#include <bits/stdc++.h>
constexpr int N = 1005;
using namespace std;
int a , b , n , ans , v[N][N];
deque<int> d[N] , D[N];
deque<pair<int , int>>q , Q;
int main() {
ios :: sync_with_stdio(0) , cin.tie(0) , cout.tie(0);
cin >> a >> b >> n;
for(register int i = 1; i <= a; ++i) {
d[i].clear() , D[i].clear();
for(register int j = 1; j <= b; ++j) {
cin >> v[i][j];
}
}
ans = 0x3f3f3f3f;
for(register int i = 1; i <= b; ++i) {
q.clear() , Q.clear();
for(register int j = 1; j <= a; ++j) {
while(!d[j].empty() && v[j][i] > v[j][d[j].back()]) {
d[j].pop_back();
}
d[j].push_back(i);
if(i >= n) {
while(!d[j].empty() && d[j].front() <= i - n) {
d[j].pop_front();
}
}
while(!D[j].empty() && v[j][i] < v[j][D[j].back()]) {
D[j].pop_back();
}
D[j].push_back(i);
if(i >= n) {
while(!D[j].empty() && D[j].front() <= i - n) {
D[j].pop_front();
}
}
}
if(i >= n) {
for(register int j = 1; j <= a; ++j) {
while(!q.empty() && v[j][d[j].front()] > v[q.back().first][q.back().second]) {
q.pop_back();
}
q.push_back({j , d[j].front()});
if(j >= n) {
while(!q.empty() && q.front().first <= j - n) {
q.pop_front();
}
}
while(!Q.empty() && v[j][D[j].front()] < v[Q.back().first][Q.back().second]) {
Q.pop_back();
}
Q.push_back({j , D[j].front()});
if(j >= n) {
while(!Q.empty() && Q.front().first <= j - n) {
Q.pop_front();
}
}
if(j >= n) {
ans = min(ans , v[q.front().first][q.front().second] - v[Q.front().first][Q.front().second]);
}
}
}
}
cout << ans;
return 0;
}