题目
https://www.luogu.org/problemnew/show/P2216
思路
X[][]与x[][]所存储的分别是1×n的长方形内的最大值,最小值。X[i][j]存储第i行第jj+n-1列的长方形中的最大值。同理,x[i][j]存储第i行第jj+n-1列的长方形中的最小值。
这时再对这两个数组的每一列上的值进行维护,将X[][]中每个区间的的最大值用Y[][]维护,将x[][]中的每个区间的最小值用y[][]维护。那么Y[i][j]存储X[][]中第ii+n-1行第j列的长方形的最大值。同理y[i][j]存储x[][]中第ii+n-1行第j列的长方形的最小值。
发现都可以用单调队列维护
代码
#include <bits/stdc++.h>
using namespace std;
int n,m,k,head,HEAD,tail,TAIL,ans;
int a[1001][1001],q[1001],Q[1001];
int x[1001][1001],X[1001][1001];
int y[1001][1001],Y[1001][1001];
int main()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
scanf("%d",&a[i][j]);
for(int i=1; i<=n; i++)
{
HEAD=TAIL=head=tail=Q[1]=q[1]=1;
for(int j=2; j<=m; j++)
{
while(a[i][j]>=a[i][Q[TAIL]]&&HEAD<=TAIL) TAIL--;
while(a[i][j]<=a[i][q[tail]]&&head<=tail) tail--;
TAIL++;tail++;Q[TAIL]=j;q[tail]=j;
while(j-Q[HEAD]>=k) HEAD++;
while(j-q[head]>=k) head++;
if(j>=k) X[i][j-k+1]=a[i][Q[HEAD]],x[i][j-k+1]=a[i][q[head]];
}
}
for(int i=1; i<=m-k+1; i++)
{
HEAD=TAIL=head=tail=Q[1]=q[1]=1;
for(int j=2; j<=n; j++)
{
while(X[j][i]>=X[Q[TAIL]][i]&&HEAD<=TAIL) TAIL--;
while(x[j][i]<=x[q[tail]][i]&&head<=tail) tail--;
TAIL++;tail++;Q[TAIL]=j;q[tail]=j;
while(j-Q[HEAD]>=k) HEAD++;
while(j-q[head]>=k) head++;
if(j>=k) Y[j-k+1][i]=X[Q[HEAD]][i],y[j-k+1][i]=x[q[head]][i];
}
}
ans=0x3f3f3f3f;
for(int i=1; i<=n-k+1; i++)
for(int j=1; j<=m-k+1; j++)
ans=min(ans,Y[i][j]-y[i][j]);
printf("%d\n",ans);
return 0;
}