#include<stdio.h>
#include<algorithm>
#define maxn 305
#define maxq 20005
using namespace std;
FILE*f=fopen("matrice2.in","r");
FILE*g=fopen("matrice2.out","w");
int n,q,i,j,val_max,x1,y1,x2,y2,puncte,iv,jv,d,viz[maxn][maxn];
int A[maxn][maxn],sol[maxq],T[maxn*maxn],rg[maxn*maxn];
int di[] = {-1,0,1,0};
int dj[] = {0,1,0,-1};
inline int point ( int x , int y ){
int p = (x-1)*n + y;
return p;
}
struct _query{
_query(int p1 = 0,int p2 = 0,int p = 0,int u = 0,int ind = 0):p1(p1),p2(p2),p(p),u(u),ind(ind){}
int p1,p2;
int p,u;
int ind;
friend bool operator < ( const _query &a , const _query &b ){
return ((a.p+a.u)>>1) < ((b.p+b.u)>>1);
}
}Q[maxq];
struct _punct{
_punct(int x = 0,int y = 0):x(x),y(y){}
int x,y;
friend bool operator < ( const _punct &a , const _punct &b ){
return A[a.x][a.y] < A[b.x][b.y];
}
}P[maxn*maxn];
inline void citire () {
fscanf(f,"%d %d",&n,&q);
for ( i = 1 ; i <= n ; ++i ){
for ( j = 1 ; j <= n ; ++j ){
fscanf(f,"%d",&A[i][j]);
val_max = max(val_max,A[i][j]);
P[++puncte] = _punct(i,j);
}
}
for ( i = 1 ; i <= q ; ++i ){
fscanf(f,"%d %d %d %d",&x1,&y1,&x2,&y2);
Q[i] = _query(point(x1,y1),point(x2,y2),1,val_max,i);
}
}
inline void unify ( int r1 , int r2 ){
if ( rg[r1] > rg[r2] ){
T[r2] = r1;
}
else{
T[r1] = r2;
}
if ( rg[r1] == rg[r2] ){
++rg[r2];
}
}
inline int root ( int x ){
int r;
for ( r = x ; T[r] != r ; r = T[r] );
while ( T[x] != x ){
int aux = T[x];
T[x] = r;
x = aux;
}
return r;
}
inline void solve () {
int finished = 0, p;
sort(P+1,P+puncte+1);
do{
sort(Q+1,Q+q+1); finished = 1; p = q + 1;
for ( i = 1 ; i <= puncte ; ++i ){
T[i] = i; rg[i] = 1;
}
for ( i = 1 ; i <= n ; ++i ){
for ( j = 1 ; j <= n ; ++j ){
viz[i][j] = 0;
}
}
for ( i = puncte ; i >= 0 ; --i ){
if ( A[P[i].x][P[i].y] != A[P[i+1].x][P[i+1].y] && A[P[i+1].x][P[i+1].y] ){
while ( ((Q[p-1].p+Q[p-1].u)>>1) > A[P[i].x][P[i].y] && p ){
--p;
if ( !Q[p].ind ) continue ;
if ( root(Q[p].p1) == root(Q[p].p2) ){
Q[p].p = ((Q[p].p+Q[p].u)>>1) + 1;
}
else{
Q[p].u = ((Q[p].p+Q[p].u)>>1) - 1;
}
if ( Q[p].p <= Q[p].u ){
finished = 0;
}
else{
sol[Q[p].ind] = Q[p].u;
Q[p].ind = 0;
}
}
}
viz[P[i].x][P[i].y] = 1;
for ( d = 0 ; d < 4 ; ++d ){
iv = P[i].x + di[d]; jv = P[i].y + dj[d];
if ( iv >= 1 && iv <= n && jv >= 1 && jv <= n && viz[iv][jv] ){
int r1 = root(point(P[i].x,P[i].y));
int r2 = root(point(iv,jv));
if ( r1 != r2 ){
unify(r1,r2);
}
}
}
}
}while(!finished);
for ( i = 1 ; i <= q ; ++i ){
fprintf(g,"%d\n",sol[i]);
}
}
int main () {
citire();
solve();
fclose(f);
fclose(g);
return 0;
}