#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<iostream>
#include<algorithm>
#include<deque>
#include<queue>
#include<set>
#include<vector>
using namespace std;
const int INF = 1000000005;
const int NMAX = 305;
const int HMAX = 1000005;
const int lgHMAX = 22;
const int QMAX = 20005;
const int LINMAX = 10000;
int N, Q;
int a[NMAX][NMAX];
int x1, f1, x2, f2;
int rez[NMAX][NMAX];
int lin[] = {-1, 0, 0, 1};
int col[] = {0, -1, 1, 0};
pair<int, int> poz[NMAX*NMAX];
pair<int, int> tata[NMAX][NMAX];
int exista[HMAX], hm, NR = 1;
int c[QMAX][5], sol[QMAX];
int rg[NMAX][NMAX];
char cit[LINMAX];
inline bool nul(pair<int, int> x)
{
if(!x.first && !x.second)
return 1;
return 0;
}
inline bool cmp(pair<int, int> x, pair<int, int> y)
{
return a[x.first][x.second] >= a[y.first][y.second];
}
void citi()
{
scanf("%d %d\n", &N, &Q);
for(int i = 1 ; i <= N ; i++)
{
int val[NMAX], nr = 0, x = 0;
gets(cit);
for(int k = 0; cit[k] ; k++)
if('0' <= cit[k] && cit[k] <= '9')
x = 10 * x + cit[k] - '0';
else
val[++nr] = x, x = 0;
if(nr < N)
val[++nr] = x;
for(int j = 1 ; j <= N ; j++)
{
a[i][j] = val[j];
poz[(i - 1)*N + j] = make_pair(i, j);
exista[a[i][j]]++;
hm = max(hm, a[i][j]);
}
}
for(int i = 1 ; i <= Q ; i++)
{
int val[NMAX], nr = 0, x = 0;
gets(cit);
for(int k = 0; cit[k] ; k++)
if('0' <= cit[k] && cit[k] <= '9')
x = 10 * x + cit[k] - '0';
else
val[++nr] = x, x = 0;
if(nr < 4)
val[++nr] = x;
c[i][1] = val[1];
c[i][2] = val[2];
c[i][3] = val[3];
c[i][4] = val[4];
}
}
inline bool in(int x, int y)
{
if(1 <= x && x <= N && 1 <= y && y <= N)
return 1;
return 0;
}
inline pair<int, int> find(int x, int y)
{
pair<int, int> rad = tata[x][y];
for(; rad != tata[rad.first][rad.second]; rad = tata[rad.first][rad.second]);
while(x != tata[x][y].first || y != tata[x][y].second)
{
int x1 = x, y1 = y;
x = tata[x1][y1].first;
y = tata[x1][y1].second;
tata[x1][y1] = rad;
}
return rad;
}
inline void unite(pair<int, int> x, pair<int, int> y)
{
if(rg[x.first][x.second] > rg[y.first][y.second])
tata[y.first][y.second] = x;
else
tata[x.first][x.second] = y;
if(rg[x.first][x.second] == rg[y.first][y.second])
rg[y.first][y.second]++;
}
void init()
{
for(int i = 1 ; i <= N ; i++)
for(int j = 1 ; j <= N ; j++)
{
rez[i][j] = rg[i][j] = 0;
tata[i][j] = make_pair(0, 0);
}
}
void padure(int H)
{
for(int NR = 1 ; a[poz[NR].first][poz[NR].second]>= H ; NR++)
{
int x = poz[NR].first, y = poz[NR].second;
rez[x][y] = 1;
tata[x][y] = make_pair(x, y);
rg[x][y] = 1;
for(int k = 0 ; k <= 3 ; k++)
if(in(x + lin[k], y + col[k]) && rez[x + lin[k]][y + col[k]])
unite(find(x, y), find(x + lin[k], y + col[k]));
}
}
void caut_bin(int q)
{
int P = 1<<lgHMAX, REZ = 0;
while(P > hm)
P >>= 1;
while(P)
{
if(REZ + P <= hm)
{
init();
padure(REZ + P);
pair<int, int> x = find(c[q][1], c[q][2]), y = find(c[q][3], c[q][4]);
if(!nul(x) && !nul(y) && x == y)
REZ += P;
}
P >>= 1;
}
sol[q] = REZ;
}
void scrie()
{
for(int i = 1 ; i <= Q ; i++)
printf("%d\n", sol[i]);
}
int main()
{
freopen("matrice2.in", "r", stdin);
freopen("matrice2.out", "w", stdout);
citi();
a[0][0] = INF;//ma ajuta la soratre , car face fite
sort(poz, poz + N * N + 1, cmp);
for(int i = 1 ; i <= Q ; i++)
caut_bin(i);
scrie();
return 0;
}