新技能单调队列get。。想了好久单调队列才想明白,,真是傻逼。。先用单调队列对每一个位置求出同行前面n个数的最大最小,这样就等于把n个数缩成了一个数,然后在对列用单调队列类似的搞一下就行了。。
#include<iostream>
#include<cstdio>
#include<memory.h>
#define N 1005
#define h1 qmin[head1]
#define h2 qmax[head2]
#define t1 qmin[tail1]
#define t2 qmax[tail2]
using namespace std;
struct num{
int x,y;
} qmin[N],qmax[N],minm,maxm;
int i,j,k,a,b,n,head1,tail1,head2,tail2,lmin[N][N],lmax[N][N],c[N][N],ans;
void ins(int x,int y)
{
while (head1<=tail1&&c[t1.x][t1.y]>c[x][y]) tail1--;tail1++;
t1.x=x;t1.y=y;
while (head2<=tail2&&c[t2.x][t2.y]<c[x][y]) tail2--;tail2++;
t2.x=x;t2.y=y;
}
void get(int x,int y)
{
while (head1<=tail1&&y-h1.y>=n) head1++;
minm=h1;
while (head2<=tail2&&y-h2.y>=n) head2++;
maxm=h2;
}
void ins2(int x,int y)
{
while (head1<=tail1&&lmin[t1.x][t1.y]>lmin[x][y]) tail1--;tail1++;
t1.x=x;t1.y=y;
while (head2<=tail2&&lmax[t2.x][t2.y]<lmax[x][y]) tail2--;tail2++;
t2.x=x;t2.y=y;
}
void get2(int x,int y)
{
while (head1<=tail1&&x-h1.x>=n) head1++;
minm=h1;
while (head2<=tail2&&x-h2.x>=n) head2++;
maxm=h2;
}
int main()
{
scanf("%d%d%d",&a,&b,&n);
for (i=1;i<=a;i++)
for (j=1;j<=b;j++)
scanf("%d",&c[i][j]);
for (i=1;i<=a;i++)
{
head1=head2=1;tail2=tail1=0;
for (j=1;j<=b;j++)
{
ins(i,j);get(i,j);
lmin[i][j]=c[minm.x][minm.y];lmax[i][j]=c[maxm.x][maxm.y];
// printf("%d ",c[maxm.x][maxm.y]);
}
// printf("\n");
}
ans=1000000001;
for (j=1;j<=b;j++)
{
head1=head2=1;tail2=tail1=0;
for (i=1;i<=a;i++)
{
ins2(i,j);get2(i,j);
if (i>=n&&j>=n)ans=min(ans,lmax[maxm.x][maxm.y]-lmin[minm.x][minm.y]);
}
}
printf("%d",ans);
}