#include <stdio.h>
#include <algorithm>
#include <vector>
#define NMAX 305
#define LMAX 20005
#define HMAX 300505
#define KMAX 1000005
#define pb push_back
using namespace std;
int n,q,A[NMAX][NMAX],r,root[HMAX];
struct query{int x1,y1,x2,y2;};
query B[LMAX];
struct pereche{int a,b;};
pereche C[HMAX];
vector <int> D[KMAX];
inline int code(int x,int y)
{
return (x<<10)+y;
}
int dlin[]={0,0,-1,1};
int dcol[]={-1,1,0,0};
void read()
{
scanf("%d%d",&n,&q);
int i,j;
for (i=1; i<=n; i++)
for (j=1; j<=n; j++)
{
scanf("%d",&A[i][j]);
D[A[i][j]].pb(code(i,j));
}
for (i=1; i<=q; i++)
scanf("%d%d%d%d",&B[i].x1,&B[i].y1,&B[i].x2,&B[i].y2);
for (i=1; i<=q; i++)
C[i].b=i;
}
bool comp(pereche x,pereche y)
{
return x.a>y.a;
}
bool comp2(pereche x,pereche y)
{
return x.b<y.b;
}
void reset_values()
{
int i;
for (i=1; i<HMAX; i++)
root[i]=i;
}
int find_root(int nod)
{
int nod2=nod,act;
while (root[nod2]!=nod2)
nod2=root[nod2];
while (root[nod]!=nod)
{
act=root[nod];
root[nod]=nod2;
nod=act;
}
return nod2;
}
void uneste(int nod1,int nod2)
{
root[nod1]=nod2;
}
void solve()
{
int i,j,k,t,step,lin,col,act,lin2,col2,ind,which;
for (step=1; step<=KMAX; step<<=1);
for ( ; step; step>>=1)
{
reset_values();
ind=0;
for (j=1; j<=q; j++)
{
C[j].a+=step;
if (C[j].a>=KMAX)
C[j].a-=step;;
}
sort(C+1,C+q+1,comp);
for (j=KMAX-1; j>=1; j--)
{
for (k=0; k<D[j].size(); k++)
{
act=D[j][k];
lin=act>>10; col=act-(lin<<10);
for (t=0; t<4; t++)
{
lin2=lin+dlin[t]; col2=col+dcol[t];
if (A[lin2][col2]>=j)
uneste(find_root(code(lin,col)),find_root(code(lin2,col2)));
}
}
while (ind+1<=q && C[ind+1].a==j)
{
ind++;
which=C[ind].b;
if (find_root(code(B[which].x1,B[which].y1))!=find_root(code(B[which].x2,B[which].y2)))
C[ind].a-=step;
}
}
}
sort(C+1,C+q+1,comp2);
for (i=1; i<=q; i++)
printf("%d\n",C[i].a);
}
int main()
{
freopen("matrice2.in","r",stdin);
freopen("matrice2.out","w",stdout);
read();
solve();
return 0;
}