#include <fstream>
#include <vector>
#include <algorithm>
using namespace std;
ifstream fin ("matrice2.in");
ofstream fout ("matrice2.out");
const int NM = 100100, M = 310;
int dx[4] = {0, 0, -1, 1};
int dy[4] = {-1, 1, 0, 0};
struct nush1{
int k,p;
}V[NM];
struct nush2{
int a, b, st, dr, ind;
}q[NM];
int i, n, m, T[NM], VA[NM], N, val, k, t1, x, ic, jc, t2, t, vm, po, R[NM], xc, A[M][M], j, yc, xu, yu;
vector<int> v[NM];
inline int cmp1(nush1 A, nush1 B) {
return A.k < B.k;
}
inline int cmp2(nush2 A, nush2 B) {
return A.a < B.a;
}
inline int cmp3(nush2 A, nush2 B) {
return A.ind < B.ind;
}
void unite(int x, int y) {
if(R[x] <= R[y]) {
T[x] = y;
if (R[x] == R[y]) {
R[y]++;
}
} else {
T[y]=x;
}
}
int find(int x) {
int aux = x;
while (x != T[x]) {
x = T[x];
}
int t = x;
x = aux;
while (x != t) {
aux = T[x];
T[x] = t;
x = aux;
}
return t;
}
int main() {
fin >> n >> m;
for (i = 1; i <= n; ++i) {
for (j = 1; j <= n; ++j) {
fin >> V[(i - 1) * n + j].k;
V[(i - 1) * n + j].p = (i - 1) * n + j;
A[i][j] = (i - 1) * n + j;
}
}
for (i = 1; i <= n; ++i) {
for(j = 1; j <= n; ++j) {
for (k = 0; k < 4; ++k) {
ic = i + dx[k];
jc = j + dy[k];
if (ic < 1 || jc < 1 || ic > n || jc > n) {
continue;
}
v[A[i][j]].push_back(A[ic][jc]);
}
}
}
N = n * n;
sort(V + 1,V + N + 1, cmp1);
for (i = 1; i <= m; ++i) {
fin >> xu >> yu >> xc >> yc;
q[i].st = A[xu][yu];
q[i].dr = A[xc][yc];
q[i].ind = i;
}
vm = V[N].k;
for (i = 1; i <= N; ++i) {
VA[V[i].p] = V[i].k;
}
for (po = 1; po <= vm; po <<= 1);
po >>= 1;
for (; po; po >>= 1) {
j = N;
sort(q + 1, q + m + 1, cmp2);
for (i = 1; i <= N; ++i) {
R[i] = 1;
T[i] = i;
}
for (i = m; i > 0; --i) {
val = q[i].a + po;
for (; j >= 1; --j) {
if (V[j].k < val) {
break;
}
x = V[j].p;
t1 = find(x);
for (t = 0; t < v[x].size(); ++t) {
if (VA[v[x][t]] < val) {
continue;
}
t2 = find(v[x][t]);
if (t2 != t1) {
unite(t1, t2);
}
t1 = find(x);
}
}
t1 = find(q[i].st);
t2 = find(q[i].dr);
if (t1 == t2) {
q[i].a += po;
}
}
}
sort (q + 1, q + m + 1, cmp3);
for (i = 1; i <= m; ++i) {
fout << q[i].a << "\n";
}
return 0;
}