#include<iostream>
#include<fstream>
#include<vector>
#include<algorithm>
using namespace std;
#define NMAX 305
#define HMAX 1000005
#define QMAX 20005
#define pb push_back
#define mp make_pair
struct Query {
int x1,y1,x2,y2,sol,poz;
};
vector < pair < int , pair < int , int > > > a;
int p[NMAX*NMAX],lev[NMAX*NMAX],v[NMAX][NMAX],n;
Query query[QMAX];
int dx[]={0,-1,0,1,0};
int dy[]={0,0,1,0,-1};
int find(int x)
{
int aux,r;
r=x;
while(p[r]!=r)
r=p[r];
aux=x;
while(p[x]!=x) {
aux=p[x];
p[x]=r;
x=aux;
}
return r;
}
void unite(int x, int y)
{
x=find(x);
y=find(y);
if(lev[x]>=lev[y])
p[y]=x;
else p[x]=y;
if(lev[x]==lev[y])
lev[x]++;
}
inline int code(int x, int y)
{
return (x-1)*n+y;
}
inline bool cmp1(Query a, Query b)
{
return a.sol > b.sol;
}
inline bool cmp2(Query a, Query b)
{
return a.poz < b.poz;
}
void add(int index, int val)
{
int i,x,y;
x=a[index].second.first;
y=a[index].second.second;
for(i=1;i<=4;i++) {
x=x+dx[i];
y=y+dy[i];
if(x>=1 && x<=n && y>=1 && y<=n && v[x][y]>=val)
unite(code(x,y),code(x-dx[i],y-dy[i]));
x=x-dx[i];
y=y-dy[i];
}
}
int main ()
{
int m,q,i,H,step,j,x1;
ifstream f("matrice2.in");
ofstream g("matrice2.out");
f>>n>>q;
a.pb(mp(0,mp(0,0)));
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) {
f>>x1;
a.pb(mp(x1,mp(i,j)));
v[i][j]=x1;
}
for(i=1;i<=q;i++) {
f>>query[i].x1>>query[i].y1>>query[i].x2>>query[i].y2;
query[i].sol=1;
query[i].poz=i;
}
f.close();
sort(a.begin()+1,a.end());
reverse(a.begin()+1,a.end());
H=a[1].first;
for(step=1;step*2<H;step=step*2);
for( ; step; step=step/2) {
sort(query+1,query+q+1,cmp1);
for(i=1;i<=n*n;i++) {
p[i]=i;
lev[i]=0;
}
j=1;
for(i=1;i<=q;i++) {
while(j<=n*n && a[j].first>=query[i].sol+step) {
add(j,query[i].sol+step);
j++;
}
if(find(code(query[i].x1,query[i].y1))==find(code(query[i].x2,query[i].y2)))
query[i].sol=query[i].sol+step;
}
}
sort(query+1,query+q+1,cmp2);
for(i=1;i<=q;i++)
g<<query[i].sol<<'\n';
g.close();
return 0;
}