/*洛谷 U4792 Acheing 二维线段树 n*n*logn*logn T成傻逼2333 */ #include<iostream> #include<cstdio> #include<cstring> #define maxn 1010 #define lc k*2 #define rc k*2+1 #define mid (l+r)/2 using namespace std; int n,m,k,g[maxn][maxn],x,y,z; int x1,x2,y1,y2,ans=0x7fffffff; int mx[maxn*4][maxn*4],mxx[maxn*4][maxn*4]; void Insert_y(int kx,int k,int l,int r){ mx[kx][k]=min(mx[kx][k],z); mxx[kx][k]=max(mxx[kx][k],z); if(l==r)return; if(y<=mid)Insert_y(kx,lc,l,mid); else Insert_y(kx,rc,mid+1,r); mx[kx][k]=min(mx[kx][lc],mx[kx][rc]); mxx[kx][k]=max(mxx[kx][lc],mxx[kx][rc]); } void Insert_x(int k,int l,int r){ Insert_y(k,1,1,m); if(l==r)return; if(x<=mid)Insert_x(lc,l,mid); else Insert_x(rc,mid+1,r); } int Query_miny(int kx,int k,int l,int r){ if(y1<=l&&y2>=r)return mx[kx][k]; if(y2<=mid)return Query_miny(kx,lc,l,mid); else if(y1>mid)return Query_miny(kx,rc,mid+1,r); else return min(Query_miny(kx,lc,l,mid),Query_miny(kx,rc,mid+1,r)); } int Query_maxy(int kx,int k,int l,int r){ if(y1<=l&&y2>=r)return mxx[kx][k]; if(y2<=mid)return Query_maxy(kx,lc,l,mid); else if(y1>mid)return Query_maxy(kx,rc,mid+1,r); else return max(Query_maxy(kx,lc,l,mid),Query_maxy(kx,rc,mid+1,r)); } int Query_minx(int k,int l,int r){ if(x1<=l&&x2>=r)return Query_miny(k,1,1,m); if(x2<=mid)return Query_minx(lc,l,mid); else if(x1>mid)return Query_minx(rc,mid+1,r); else return min(Query_minx(lc,l,mid),Query_minx(rc,mid+1,r)); } int Query_maxx(int k,int l,int r){ if(x1<=l&&x2>=r)return Query_maxy(k,1,1,m); if(x2<=mid)return Query_maxx(lc,l,mid); else if(x1>mid)return Query_maxx(rc,mid+1,r); else return max(Query_maxx(lc,l,mid),Query_maxx(rc,mid+1,r)); } int main() { scanf("%d%d%d",&n,&m,&k); memset(mxx,-127/3,sizeof(mxx)); memset(mx,127/3,sizeof(mx)); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ scanf("%d",&g[i][j]); x=i;y=j;z=g[i][j]; Insert_x(1,1,n); } for(int i=k;i<=n;i++) for(int j=k;j<=m;j++){ x1=i-k+1;x2=i;y1=j-k+1;y2=j; int minner=Query_minx(1,1,n); int maxxer=Query_maxx(1,1,n); ans=min(ans,maxxer-minner); } printf("%d ",ans); return 0; }
/*洛谷 U4792 Acheing 单调队列运用 解决二维线段树超时的问题 */ #include<cstdio> #include<cstring> #define maxn 1010 using namespace std; int n,m,k,g[maxn][maxn],mx[maxn][maxn],mi[maxn][maxn],mxx[maxn][maxn],mxi[maxn][maxn]; int q[maxn],head,tail,ans=0x7fffffff; int init(){ int x=0,f=1;char s=getchar(); while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();} while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();} return x*f; } int min(int x,int y){ return x<y?x:y; } void Ready(){ for(int j=1;j<=m;j++){ head=1;tail=0; for(int i=1;i<=n;i++){ int x=g[i][j]; while(head<=tail&&x>g[q[tail]][j])tail--; q[++tail]=i; if(i-q[head]>=k)head++; mx[i][j]=g[q[head]][j]; } } for(int j=1;j<=m;j++){ head=1;tail=0; for(int i=1;i<=n;i++){ int x=g[i][j]; while(head<=tail&&x<g[q[tail]][j])tail--; q[++tail]=i; if(i-q[head]>=k)head++; mi[i][j]=g[q[head]][j]; } } } void Solve(){ for(int i=k;i<=n;i++){ head=1;tail=0; for(int j=1;j<=m;j++){ int x=mx[i][j]; while(head<=tail&&x>mx[i][q[tail]])tail--; q[++tail]=j; if(j-q[head]>=k)head++; mxx[i][j]=mx[i][q[head]]; } } for(int i=k;i<=n;i++){ head=1;tail=0; for(int j=1;j<=m;j++){ int x=mi[i][j]; while(head<=tail&&x<mi[i][q[tail]])tail--; q[++tail]=j; if(j-q[head]>=k)head++; mxi[i][j]=mi[i][q[head]]; } } } int main() { n=init();m=init();k=init(); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) g[i][j]=init(); Ready();Solve(); for(int i=k;i<=n;i++) for(int j=k;j<=m;j++) ans=min(ans,mxx[i][j]-mxi[i][j]); printf("%d ",ans); return 0; }