[HAOI理想的正方形][单调队列]

HAOI2007理想的正方形
先像滑动窗口一样处理出每一行的mx mn
然后再一列一列来

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define Max(x,y) ((x)>(y)?(x):(y))
#define Min(x,y) ((x)<(y)?(x):(y))
const int N=1000+50,M=1e6+50,inf=0x3f3f3f3f,P=19650827;
int a,b,n,k,ans=inf,mp[N][N],mxh[N][N],mnh[N][N],mx[N][N],mn[N][N];
template <class t>void rd(t &x){
    x=0;int w=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x=w?-x:x;
}

int main(){
	freopen("in2.txt","r",stdin);
	rd(a),rd(b),rd(n);
	for(int i=1;i<=a;++i)
	for(int j=1;j<=b;++j) rd(mp[i][j]);
	int l1,l2,r1,r2,q1[N],q2[N];
	for(int h=1;h<=a;++h){	
		l1=l2=1,r1=r2=0;
	memset(q1,0,sizeof(q1));memset(q2,0,sizeof(q2));
		for(int i=1;i<=b;++i){
  	        while(l1<=r1&&mp[h][i]<mp[h][q1[r1]]) --r1;
   	        while(l2<=r2&&mp[h][i]>mp[h][q2[r2]]) --r2;
   	        while(l1<=r1&&q1[l1]<=i-n) ++l1;
   	        while(l2<=r2&&q2[l2]<=i-n) ++l2;
   	        q1[++r1]=i,q2[++r2]=i;
			if(l1<=r1&&i>=n) mnh[h][i]=mp[h][q1[l1]];
			if(l2<=r2&&i>=n) mxh[h][i]=mp[h][q2[l2]];
  	  }
	}
	for(int l=n;l<=b;++l){
		l1=l2=1,r1=r2=0;
	memset(q1,0,sizeof(q1));memset(q2,0,sizeof(q2));
		for(int i=1;i<=a;++i){
			while(l1<=r1&&mnh[i][l]<mnh[q1[r1]][l]) --r1;
        	while(l2<=r2&&mxh[i][l]>mxh[q2[r2]][l]) --r2;
        	while(l1<=r1&&q1[l1]<=i-n) ++l1;
        	while(l2<=r2&&q2[l2]<=i-n) ++l2;
        	q1[++r1]=i,q2[++r2]=i;
        	if(l1<=r1) mn[i][l]=mnh[q1[l1]][l];
        	if(l2<=r2) mx[i][l]=mxh[q2[l2]][l];
	    }		
	}
	for(int i=n;i<=a;++i)
	for(int j=n;j<=b;++j){
		ans=Min(ans,mx[i][j]-mn[i][j]);
		if(!ans) break;
	}
	printf("%d",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/lxyyyy/p/11425086.html