#include <bits/stdc++.h>
#define id(x, y) ((x) * n + y)
using namespace std;
int n, m;
vector <pair <int, int>> dir = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };
const int NMAX = 310 * 310;
namespace UF {
int tata[NMAX], g[NMAX];
bool activ[NMAX];
int find(int x) {
if (!activ[x])
return x;
if (tata[tata[x]] != tata[x])
tata[x] = find(tata[x]);
return tata[x];
}
void unite(int a, int b) {
a = find(a);
b = find(b);
if (a == b)
return;
if (g[a] >= g[b])
tata[b] = a, g[a] += g[b];
else
tata[a] = b, g[b] += g[a];
}
void add(int x, int y) {
int nr = id(x, y);
activ[nr] = 1;
tata[nr] = nr, g[nr] = 1;
for (auto i : dir)
if (activ[id(x + i.first, y + i.second)])
unite(nr, id(x + i.first, y + i.second));
}
void reset() {
memset(tata, 0, sizeof tata);
memset(activ, 0, sizeof activ);
memset(g, 0, sizeof g);
}
bool same(int x1, int y1, int x2, int y2) {
return find(id(x1, y1)) == find(id(x2, y2));
}
}
struct Q {
int x1, y1, x2, y2, t, id;
bool operator< (const Q & x) const {
return t < x.t;
}
};
vector <Q> events;
vector <tuple <int, int, int>> v;
int main()
{
ifstream in("matrice2.in");
ofstream out("matrice2.out");
int x;
in >> n >> m;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
in >> x;
v.push_back(make_tuple(x, i, j));
}
}
sort(v.rbegin(), v.rend());
events.resize(m);
for (int i = 0; i < m; i++) {
in >> events[i].x1 >> events[i].y1;
in >> events[i].x2 >> events[i].y2;
events[i].id = i;
events[i].t = 0;
}
for (int q = 20; q >= 0; q--) {
for (auto & i : events)
i.t += (1 << q);
for (int i = 0, j = 0; i < events.size(); i++) {
//cout << get <0> (v[j]) << ' ' << events[i].t << '\n';
while (j < v.size() && get <0> (v[j]) >= events[i].t) {
UF::add(get <1> (v[j]), get <2> (v[j]));
j++;
// cout << get <0> (v[j]) << '\n';
}
if (!UF::same(events[i].x1, events[i].y1,
events[i].x2, events[i].y2))
events[i].t -= (1 << q);
}
UF::reset();
sort(events.rbegin(), events.rend());
}
vector <int> ans(m);
for (auto i : events)
ans[i.id] = i.t;
for (auto i : ans)
out << i << '\n';
return 0;
}