using namespace std;
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#define NrMax 100000
int N, Q, Pmax, nr;
int A[NrMax], ind[NrMax], T[20][NrMax], TT[NrMax], lvl[NrMax];
char W[NrMax];
vector<int> G[NrMax];
int Qe[NrMax];
int cmp(const int &a, const int &b) { return A[a] > A[b]; }
void citire()
{
int i, j;
freopen("matrice2.in","r",stdin);
scanf("%d %d\n",&N,&Q);
for (i=1; i<=N; ++i)
for (j=1; j<=N; ++j)
{
scanf("%d",&A[++nr]);
ind[nr] = TT[nr] = nr;
}
}
int tata(int nod)
{
if (TT[nod] == nod) return TT[nod];
return TT[nod] = tata(TT[nod]);
}
void disjoint()
{
int i, nod, t1;
for (i=1; i<=nr; ++i)
{
nod = ind[i];
W[nod] = 1;
if ((nod-1)%N && W[nod-1])
{
t1 = tata(nod-1);
if (t1!=nod)
T[0][t1] = TT[t1] = nod;
G[nod].push_back(t1);
}
if (nod>N && W[nod-N])
{
t1 = tata(nod-N);
if (t1!=nod)
T[0][t1] = TT[t1] = nod,
G[nod].push_back(t1);
}
if (nod%N && W[nod+1])
{
t1 = tata(nod+1);
if (t1!=nod)
T[0][t1] = TT[t1] = nod,
G[nod].push_back(t1);
}
if (nod+N<=nr && W[nod+N])
{
t1 = tata(nod+N);
if (t1!=nod)
T[0][t1] = TT[t1] = nod,
G[nod].push_back(t1);
}
}
}
void stramosi()
{
int p, i;
for (p=1; (1<<p)<=nr; ++p)
for (i=1; i<=nr; ++i)
T[p][i] = T[p-1][T[p-1][i]];
Pmax = p;
}
void dfs(int nod)
{
vector<int>::iterator it;
lvl[nod] = lvl[T[0][nod]] + 1;
for (it=G[nod].begin(); it<G[nod].end(); ++it)
dfs(*it);
}
int lca(int a, int b)
{
int aux, p, nod;
//vino pe acelasi nivel
if (lvl[a]<lvl[b]) { aux=a; a=b; b=aux; }
nod = a;
p = Pmax;
while (p)
{
if (lvl[T[p-1][nod]] >= lvl[b]) nod=T[p-1][nod];
--p;
}
a = nod;
//gaseste lca
p = Pmax;
while (p)
{
if (T[p-1][a] != T[p-1][b])
a=T[p-1][a],
b=T[p-1][b];
--p;
}
if (a!=b) a=T[0][a];
return a;
}
void brut_force(int a, int b)
{
int p = 1, st, dr, nod, rez = nr;
while (p<=nr) p<<=1;
p>>=1;
while (p)
{
memset(W, 0, sizeof(W));
Qe[st=dr=0] = a;
//printf(" %d\n",A[ind[rez-p]]);
while (st<=dr)
{
nod = Qe[st];
++st;
if (A[nod] < A[ind[rez-p]]) continue;
if ((nod-1)%N && !W[nod-1]) W[ Qe[++dr] = nod-1 ] = 1;
if (nod>N && !W[nod-N]) W[ Qe[++dr] = nod - N ] = 1;
if (nod%N && !W[nod+1]) W[ Qe[++dr] = nod + 1 ] = 1;
if (nod+N <= nr && !W[nod+N]) W[ Qe[++dr] = nod+N ] = 1;
}
if (W[b] && A[b] >= A[ind[rez-p]]) rez-=p;
p>>=1;
while (rez-p<=0) p>>=1;
}
printf("%d\n",A[ind[rez]]);
}
int main()
{
int i, x1, y1, x2, y2;
citire();
sort(ind+1, ind+nr+1, cmp);
disjoint();
stramosi();
dfs( ind[nr] );
freopen("matrice2.out","w",stdout);
for (i=0; i<Q; ++i)
{
scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
printf("%d\n", A[ lca((x1-1)*N+y1, (x2-1)*N+y2) ] );
//brut_force((x1-1)*N+y1, (x2-1)*N+y2);
}
fclose(stdout);
return 0;
}