#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int NMAX = 305;
const int QMAX = 20005;
int N,M,i,j,A[NMAX][NMAX],Cnt,step,B[NMAX][NMAX],Father[NMAX*NMAX],F1,F2;
int Dx[]={-1,0,0,1}; int Dy[]={0,-1,1,0};
struct Element {int x,y;} E[NMAX*NMAX];
struct Query {int x0,y0,x1,y1,i,sol;} Q[QMAX];
bool cmp1(Element X,Element Y)
{
return A[X.x][X.y]>A[Y.x][Y.y];
}
bool cmp2(Query X,Query Y)
{
return X.sol>Y.sol;
}
bool cmp3(Query X,Query Y)
{
return X.i<Y.i;
}
int Find(int X)
{
if(Father[X]!=X) Father[X]=Find(Father[X]);
return Father[X];
}
void Unite(int X,int Y)
{
Father[X]=Y;
}
void Unite4(int X,int Y)
{
for(int i=0;i<4;i++)
if(B[X+Dx[i]][Y+Dy[i]])
Unite(Find(B[X][Y]),Find(B[X+Dx[i]][Y+Dy[i]]));
}
int main()
{
freopen("matrice2.in","r",stdin);
freopen("matrice2.out","w",stdout);
scanf("%d%d",&N,&M);
for(i=1;i<=N;i++)
for(j=1;j<=N;j++)
{
scanf("%d",&A[i][j]);
E[++Cnt].x=i; E[Cnt].y=j;
}
sort(E+1,E+Cnt+1,cmp1);
for(i=1;i<=M;i++)
{
scanf("%d%d",&Q[i].x0,&Q[i].y0);
scanf("%d%d",&Q[i].x1,&Q[i].y1);
Q[i].i=i;
}
for(step=(1<<20);step;step>>=1)
{
sort(Q+1,Q+M+1,cmp2);
memset(B,0,sizeof(B));
for(i=1;i<=N*N;i++) Father[i]=i;
i=1; Cnt=0;
for(j=1;j<=M;j++)
{
for(;i<=N*N && A[E[i].x][E[i].y]>=Q[j].sol+step;i++)
{
B[E[i].x][E[i].y]=++Cnt;
Unite4(E[i].x,E[i].y);
}
F1=Find(B[Q[j].x0][Q[j].y0]);
F2=Find(B[Q[j].x1][Q[j].y1]);
if(F1 && F1==F2) Q[j].sol+=step;
}
}
sort(Q+1,Q+M+1,cmp3);
for(i=1;i<=M;i++) printf("%d\n",Q[i].sol);
return 0;
}