P2216理想的正方形题解

又是一道题解满了的题
按照题意,我们需要维护一个 \(n\times n\) 大小的矩阵内的最大最小值。

显然一个二维的东西不好直接维护。

我们可以先维护行的最值,然后再用单调队列维护连续\(n\)行的最值。(如果暂时不理解这句话请先看下面的操作。)

\(mx[i][j],mn[i][j]\) 分别表示 \(a[i][j]\) ~ \(a[i][j+n-1]\) 中的最大/最小值,用单调队列维护,一次维护一行,共维护 \(n\) 次,复杂度\(O(n^2)\)

然后按列维护,维护 \(mx[i][j]\) ~ \(mx[i+n-1][j]\) 的最大值以及 \(mn[i][j]\) ~ \(mn[i+n-1][j]\) 的最小值,作差取 \(max\)。这样就可以维护 \(n\times n\)的矩阵了。

\(Code\)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<deque>
#define pa pair<int,int>
#define rg register
#define ls (k<<1)
#define rs (k<<1|1)
using namespace std;
typedef long long ll;
const double eps=1e-13;
inline ll read(){
	char ch=getchar();
    ll x=0;bool f=0;
	while(ch<'0'||ch>'9')
	{
		if(ch=='-') f=1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<3)+(x<<1)+(ch^48);
		ch=getchar();
	}
	return f?-x:x;
}
int n,a,b,jz[1009][1009],mx[1009][1009],ans=2147483647,mn[1009][1009];
deque<int> q[3];//q[1]:最大值,q[2]:最小值
void push(int opt,int ps,int i){
	if(opt==1){
		while(!q[1].empty()&&jz[i][q[1].back()]<jz[i][ps]) q[1].pop_back();
		q[1].push_back(ps);
	}
	if(opt==2){
		while(!q[2].empty()&&jz[i][q[2].back()]>jz[i][ps]) q[2].pop_back();
		q[2].push_back(ps);
	}
	if(opt==3){
		while(!q[1].empty()&&mx[q[1].back()][i]<mx[ps][i]) q[1].pop_back();
		q[1].push_back(ps);
	}
	if(opt==4){
		while(!q[2].empty()&&mn[q[2].back()][i]>mn[ps][i]) q[2].pop_back();
	    q[2].push_back(ps);
	}
}
int main()
{
   a=read();b=read();n=read();
   for(int i=1;i<=a;i++) for(int j=1;j<=b;j++) jz[i][j]=read();
   for(int i=1;i<=a;i++){//按行维护
   	   while(!q[1].empty()) q[1].pop_front();//把上一行的清空
   	   while(!q[2].empty()) q[2].pop_front();
   	   for(int j=1;j<n;j++) push(1,j,i),push(2,j,i);
	   for(int j=n;j<=b;j++){
	   	  while(!q[1].empty()&&q[1].front()<j-n+1) q[1].pop_front();
	   	  while(!q[2].empty()&&q[2].front()<j-n+1) q[2].pop_front();
	   	  push(1,j,i);push(2,j,i);
	   	  mx[i][j-n+1]=jz[i][q[1].front()];
	   	  mn[i][j-n+1]=jz[i][q[2].front()];

	   }
   }
   for(int i=1;i<=b-n+1;i++){//因为只有[1,b-n+1]之间的列有mx,mn值,所以只循环到b-n+1
    while(!q[1].empty()) q[1].pop_front();//清空上一列
    while(!q[2].empty()) q[2].pop_front();
   	for(int j=1;j<n;j++) push(3,j,i),push(4,j,i);
   	for(int j=n;j<=a;j++){
   		while(!q[1].empty()&&q[1].front()<j-n+1) q[1].pop_front();
   		while(!q[2].empty()&&q[2].front()<j-n+1) q[2].pop_front();
   		push(3,j,i);push(4,j,i);
   		ans=min(ans,mx[q[1].front()][i]-mn[q[2].front()][i]);
	   }
   }
   printf("%d\n",ans);
}
posted @ 2020-08-15 19:41  千载煜  阅读(115)  评论(0编辑  收藏  举报