[单调队列]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;
}
posted @ 2025-05-03 17:06  「癔症」  阅读(9)  评论(0)    收藏  举报