#include <bits/stdc++.h>
#define Qmax 100005
#define Nmax 302
using namespace std;
ifstream f("matrice2.in");
ofstream g("matrice2.out");
int N, K, Q;
int a[Nmax][Nmax];
bool vis[Nmax * Nmax];
struct query{
int le, ri, mid, pos, ans, x, y;
};
query q[Qmax];
bool cmp1(query a, query b) {
return a.mid < b.mid;
}
bool cmp2(query a, query b) {
return a.pos < b.pos;
}
struct cell{
int x, y, val;
};
cell v[Nmax * Nmax];
bool cmp3(cell a, cell b) {
return a.val < b.val;
}
///
int h[Nmax * Nmax], t[Nmax * Nmax];
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};
int root(int x) {
while (t[x]) x = t[x];
return x;
}
int Pos(int x, int y) {
return (x - 1) * N + y;
}
bool in(int i, int j) {
if (i < 1 || i > N) return 0;
if (j < 1 || j > N) return 0;
return 1;
}
void unite(int x, int y) {
int rx = root(x), ry = root(y);
if (h[rx] < h[ry]) swap(rx, ry);
t[ry] = rx;
if (h[rx] == h[ry]) ++h[rx];
}
int main()
{
f >> N >> Q;
for (int i = 1; i <= N; ++i)
for (int j = 1; j <= N; ++j) {
f >> a[i][j];
v[++K] = {i, j, a[i][j]};
}
sort(v + 1, v + K + 1, cmp3);
for (int i = 1; i <= Q; ++i) {
int x1, y1, x2, y2;
f >> x1 >> y1 >> x2 >> y2;
q[i].pos = i;
q[i].le = 1, q[i].ri = K, q[i].mid = (K + 1) / 2;
q[i].x = Pos(x1, y1), q[i].y = Pos(x2, y2);
}
bool ok = 1;
while (ok) {
for (int i = 1; i <= K; ++i)
h[i] = t[i] = vis[i] = 0;
sort(q + 1, q + Q + 1, cmp1);
int j = Q;
for (int i = K; i >= 1; --i) {
vis[Pos(v[i].x, v[i].y)] = 1;
for (int p = 0; p < 4; ++p) {
int lin = v[i].x + dx[p], col = v[i].y + dy[p];
if (!in(lin, col) || vis[Pos(lin,col)] == 0) continue;
int a = Pos(v[i].x, v[i].y), b = Pos(lin, col);
if (root(a) != root(b)) unite(a, b);
}
while (j && q[j].mid == i) {
if (root(q[j].x) == root(q[j].y))
q[j].ans = v[i].val, q[j].le = i + 1;
else q[j].ri = i - 1;
--j;
}
}
ok = 0;
for (int i = 1; i <= Q; ++i)
if (q[i].le <= q[i].ri) ok = 1, q[i].mid = (q[i].ri + q[i].le) / 2;
else q[i].mid = 0;
}
sort(q + 1, q + Q + 1, cmp2);
for (int i = 1; i <= Q; ++i)
g << q[i].ans << '\n';
return 0;
}