昨晚回宿舍路上Rose_max肉老师做完了这道题问我怎么做,我这么辣鸡怎么可能会做嘛。。
然后我就说:二维线段树模版题(事实上我不会写二维线段树。。)
肉老师听完,淡淡的一笑:“太不优秀了。。”
然后我想啊想,也没有想到除了二维数据结构之外的方法。
然后肉老师又淡淡一笑:“二维ST表”
然后他转身而去,留下一个背影,我在风中惘然。
对啊,二维st表。
哈哈事实上为什么可以用二维st表呢,因为我们发现a,b<=1000并且并没有修改操作,然后他是一个RMQ问题。那么st表不就很优秀吗??不懂st表的同学,可以去看一下hanks_o的博客,二维st表的话就设f[i][j][k]为(i,j)向右向上2^k的正方形的最小最大值,然后更新即可,注意这题如果是长方形就不可做了,因为要开 的空间也就是一个亿啊,会爆的。。
一开始RE了,不知道为什么,后来找hanks_o欧老师来帮我看代码,他把
for(int k=1;(1<<k)<=min(A,B);k++)
改成
for(int k=1;k<=Log[min(A,B)];k++)
就过了???为什么?
AKCqhzdy神犇在评论下已经指出:
因为
是左移
位,那么
的时候就等于
,然而
.所以应该是
所以我是sb这点就莓得说了。。。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=1010;
const int lgn =11;
const int INF =1e9;
int mymax(int a,int b,int c,int d){return max(max(max(a,b),c),d);}
int mymin(int a,int b,int c,int d){return min(min(min(a,b),c),d);}
int mx[maxn][maxn][lgn],mn[maxn][maxn][lgn];
int Log[maxn];
int A,B,n;
void st_pre()
{
for(int k=1;k<=Log[min(A,B)];k++)
for(int i=1;i+(1<<k)-1<=A;i++)
for(int j=1;j+(1<<k)-1<=B;j++)
{
mx[i][j][k]=mymax(mx[i][j][k-1],mx[i+(1<<k-1)][j][k-1],mx[i][j+(1<<k-1)][k-1],mx[i+(1<<k-1)][j+(1<<k-1)][k-1]);
mn[i][j][k]=mymin(mn[i][j][k-1],mn[i+(1<<k-1)][j][k-1],mn[i][j+(1<<k-1)][k-1],mn[i+(1<<k-1)][j+(1<<k-1)][k-1]);
}
}
int st_max(int x1,int y1,int x2,int y2)
{
int k=Log[n];
return mymax(mx[x1][y1][k],mx[x2-(1<<k)+1][y1][k],mx[x1][y2-(1<<k)+1][k],mx[x2-(1<<k)+1][y2-(1<<k)+1][k]);
}
int st_min(int x1,int y1,int x2,int y2)
{
int k=Log[n];
return mymin(mn[x1][y1][k],mn[x2-(1<<k)+1][y1][k],mn[x1][y2-(1<<k)+1][k],mn[x2-(1<<k)+1][y2-(1<<k)+1][k]);
}
int main()
{
scanf("%d%d%d",&A,&B,&n);
for(int i=1;i<=A;i++)
for(int j=1;j<=B;j++)
{
int x; scanf("%d",&x);
mx[i][j][0]=mn[i][j][0]=x;
}
Log[1]=0; for(int i=2;i<=max(A,B);i++) Log[i]=Log[i/2]+1;
st_pre();
int ans=INF;
for(int i=1;i+n-1<=A;i++)
for(int j=1;j+n-1<=B;j++)
ans=min(ans,st_max(i,j,i+n-1,j+n-1)-st_min(i,j,i+n-1,j+n-1));
printf("%d\n",ans);
return 0;
}