#include<fstream.h>
#include<algorithm>
using namespace std;
int k,n,a[100000],v[400][400],h[100000],t[100000],w[400][400],querry[100000],sol[100000],i,j,poz[100000],pz[100000],niv[100000],m;
struct point2 { int l1,c1,l2,c2; } q[50000];
inline int cmp (int x, int y) { return a[x]>a[y]; }
inline int cmp2 (int x, int y ) { return querry[x]>querry[y]; }
const int dirx[4] = {-1,0,1,0}, diry[4]= {0,-1,0,1};
void add ()
{
int r,e,l,c,q;
l=(poz[i]-1)/n;
c=(poz[i]-1)%n;
w[l][c]=1;
t[poz[i]]=poz[i];
niv[poz[i]]=1;
for (q=0;q<4; q++)
if (l+dirx[q]>=0 && l+dirx[q]<n && c+diry[q]<n && c+diry[q]>=0 && w[l+dirx[q]][c+diry[q]])
{
r=(l+dirx[q])*n+c+diry[q];
r++;
while (t[r]!=r)
r=t[r];
if (r!=t[poz[i]])
{
if (niv[t[poz[i]]]>niv[r])
t[r]=t[poz[i]];
else
if (niv[t[poz[i]]]<niv[r])
{
t[t[poz[i]]]=r;
t[poz[i]]=r;
}
else
{
niv[t[poz[i]]]++;
t[r]=t[poz[i]];
}
}
}
}
void solve()
{
int lg,e1,e2,w1,r1,r2;
for (lg=1;lg<=a[poz[1]];lg<<=1);
lg>>=1;
for (;lg;lg>>=1)
{
memset (t,0,sizeof (t));
memset (niv,0,sizeof(niv));
memset (w,0,sizeof(w));
for (i=1;i<=m;i++)
if (sol[i]+lg<=a[poz[1]])
querry[i]=sol[i]+lg;
for (i=1;i<=m;i++)
pz[i]=i;
sort (pz+1,pz+m+1,cmp2);
poz[n*n+1]=n*n+1;
a[n*n+1]=0;
for (i=1,j=1;j<=m ; )
if (a[poz[i]]>=querry[pz[j]])
{
add();
i++;
}
else
{
r1=q[pz[j]].l1*n+q[pz[j]].c1+1;
r2=q[pz[j]].l2*n+q[pz[j]].c2+1;
e1=r1;e2=r2;
while (r1!=t[r1])
r1=t[r1];
while (r2!=t[r2])
r2=t[r2];
while (e1!=r1)
{
w1=e1;
e1=t[e1];
t[w1]=r1;
}
while (e2!=r2)
{
w1=e2;
e2=t[e2];
t[w1]=r2;
}
if (r1==r2 && r1!=0)
sol[pz[j]]=querry[pz[j]];
j++;
}
}
ofstream g("matrice2.out");
for (i=1;i<=m;i++)
g<<sol[i]<<'\n';
g.close();
}
void sorteaza ()
{
int k=0,i,j;
for (i=0;i<n;i++)
for (j=0;j<n;j++)
a[++k]=v[i][j];
for (i=1;i<=k;i++)
poz[i]=i;
sort (poz+1,poz+k+1,cmp);
}
void citire ()
{
int i,j;
ifstream f("matrice2.in");
f>>n>>m;
for (i=0;i<n;i++)
for (j=0;j<n;j++)
f>>v[i][j];
for (i=1;i<=m;i++)
{
f>>q[i].l1>>q[i].c1>>q[i].l2>>q[i].c2;
q[i].l1--;
q[i].l2--;
q[i].c1--;
q[i].c2--;
}
f.close();
}
int main()
{
citire();
sorteaza();
solve ();
return 0;
}