洛谷 P2216 [HAOI2007]理想的正方形(二维单调队列)

传送门


解题思路

用二维单调队列求出每个 \(n\times n\) 矩形的最大值和最小值。
其实就是先在每一行上做原数组单调队列,再维护每一个行上最大值/最小值所组成的数组的单调队列。

AC代码

(代码写复杂了)

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<iomanip>
#include<ctime>
#include<stack>
using namespace std;
const int maxn=1005;
int n,a,b,m[maxn][maxn],ans=1e9;
deque<int> q[maxn*2],p[3];
void work(int i,int j,int type){
	if(q[i].empty()){
		q[i].push_back(j);
		return;
	}
	if(j-q[i].front()>=n) q[i].pop_front();	
	while(!q[i].empty()&&(m[i-(type==-1?a:0)][q[i].back()]*type<m[i-(type==-1?a:0)][j]*type)) q[i].pop_back();
	q[i].push_back(j);
}
void work2(int i,int type){
	if(p[type+1].empty()){
		p[type+1].push_back(i);
		return;
	}
	if(i-p[type+1].front()>=n) p[type+1].pop_front();	
	while(!p[type+1].empty()&&(m[i][q[i+(type==-1?a:0)].front()]*type>m[p[type+1].back()][q[p[type+1].back()+(type==-1?a:0)].front()]*type)) p[type+1].pop_back();
	p[type+1].push_back(i);
}
int main()
{
    ios::sync_with_stdio(false);
    cin>>a>>b>>n;
    for(int i=1;i<=a;i++){
    	for(int j=1;j<=b;j++){
    		cin>>m[i][j];
		}
	}
	for(int j=1;j<=b;j++){
		for(int i=1;i<=a;i++){
			work(i,j,1);
			work(i+a,j,-1);
		}
		if(j<n) continue;
		while(!p[0].empty()) p[0].pop_back();
		while(!p[2].empty()) p[2].pop_back();
		for(int i=1;i<=a;i++){
			work2(i,1);
			work2(i,-1);
			if(i>=n) ans=min(ans,m[p[2].front()][q[p[2].front()].front()]-m[p[0].front()][q[p[0].front()+a].front()]);
		}
	}
	cout<<ans;
    return 0;
}
posted @ 2021-08-14 17:13  尹昱钦  阅读(52)  评论(0编辑  收藏  举报