#include <fstream>
#include <cstring>
#include <algorithm>
using namespace std;
ifstream f("matrice2.in");
ofstream g("matrice2.out");
int N,M;
struct cell{
int x;
int y;
int val;
} Cell[305*305];
int F[305*305];
struct query
{
int i,x1,x2,y1,y2,s;
} Query[20005];
int TT[305*305],R[305*305],ind;
bool Valid(int x,int y)
{
return x>0 && y>0 && x<=N && y<=N;
}
int Father(int x)
{
while(F[x]!=x)
x=F[x];
while(F[x]!=x)
{
int y=F[x];
F[x]=x;
x=y;
}
return x;
}
void Unite(int x,int y)
{
if(R[x]<R[y])
F[x]=y;
else
F[y]=x;
if(R[x]==R[y])
R[x]++;
}
void Read()
{
int i;
f>>N>>M;
for(i=1;i<=N;i++)
for(int j=1;j<=N;j++)
{
Cell[++ind].x=i;
Cell[ind].y=j;
f>>Cell[ind].val;
}
for(int i=1;i<=M;i++)
{
f>>Query[i].x1>>Query[i].y1>>Query[i].x2>>Query[i].y2;
Query[i].i=i;
}
}
int Code(int x,int y)
{
return (x-1)*N+y;
}
void Insert(int x,int y)
{
int poz=Code(x,y);
F[poz]=poz;
int dx[]={-1,0,0,1};
int dy[]={0,-1,1,0};
for(int i=0;i<4;i++)
{
if(Valid(x+dx[i],y+dy[i])==0)
continue;
if(F[Code(x+dx[i],y+dy[i])]==0)
continue;
if(Father(Code(x,y))!=Father(Code(x+dx[i],y+dy[i])))
Unite(Father(Code(x,y)),Father(Code(x+dx[i],y+dy[i])));
}
}
bool cmp(query a,query b)
{
return a.s>b.s;
}
bool cmp2(query a,query b)
{
return a.i<b.i;
}
bool cmp3(cell a,cell b)
{
return a.val>b.val;
}
void binSearch()
{
int step=30,left,right;sort(Cell+1,Cell+N*N+1,cmp3);
for(step=30;step>=0;step--)
{
memset(F,0,sizeof(F));
sort(Query+1,Query+M+1,cmp);
int i=1,j=1;
for(j=1,i=1;i<=M;i++)
{
for(;j<=N*N;j++)
{
if(Query[i].s+(1<<step)<=Cell[j].val)
Insert(Cell[j].x,Cell[j].y);
else
break;
}
if(F[Code(Query[i].x1,Query[i].y1)]!=0 && Father(Code(Query[i].x1,Query[i].y1))==Father(Code(Query[i].x2,Query[i].y2)))
Query[i].s+=(1<<step);
}
}
sort(Query+1,Query+M+1,cmp2);
}
int main()
{
Read();
binSearch();
for(int i=1;i<=M;i++)
g<<Query[i].s<<"\n";
return 0;
}