#include <iostream>
#include <vector>
#include <algorithm>
#include <bitset>
#include <string.h>
using namespace std;
typedef pair<int, int> pii;
const int NMAX = 302;
int n, q;
int dx[] = {0, 0, -1, 1};
int dy[] = {1, -1, 0, 0};
struct query
{
int x1, y1, x2, y2, ans, index;
};
struct cell
{
int x, y, val;
};
vector<cell> v;
vector<query> queries;
inline int node(int x, int y)
{
return (x - 1) * n + y;
}
vector<int> t;
int find(int x)
{
if (t[x] == x)
return x;
return t[x] = find(t[x]);
}
void unite(int x, int y)
{
if (t[x] == 0 || t[y] == 0)
return;
x = find(x);
y = find(y);
if (x == y)
return;
if (x < y)
t[y] = x;
else
t[x] = y;
}
void check(int val)
{
fill(t.begin(), t.end(), 0);
int i = 0;
for (auto &q : queries)
{
while (i < n * n && v[i].val >= q.ans)
{
int x = node(v[i].x, v[i].y);
t[x] = x;
for (int k = 0; k < 4; ++k)
{
int nx = v[i].x + dx[k];
int ny = v[i].y + dy[k];
if (nx >= 1 && nx <= n && ny >= 1 && ny <= n)
{
nx = node(nx, ny);
unite(x, nx);
}
}
++i;
}
int a = find(node(q.x1, q.y1));
int b = find(node(q.x2, q.y2));
if (a == 0 || b == 0 || a != b)
q.ans -= val;
}
}
int main()
{
freopen("matrice2.in", "r", stdin);
freopen("matrice2.out", "w", stdout);
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int x;
cin >> n >> q;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
{
cin >> x;
v.push_back({i, j, x});
}
t.resize(n * n + 1);
sort(v.begin(), v.end(), [](const cell &a, const cell &b)
{ return a.val > b.val; });
int x1, y1, x2, y2;
for (int i = 0; i < q; ++i)
{
cin >> x1 >> y1 >> x2 >> y2;
queries.push_back({x1, y1, x2, y2, 0, i});
}
for (int p = (1 << 19); p; p >>= 1)
{
for (int i = 0; i < q; ++i)
queries[i].ans += p;
sort(queries.begin(), queries.end(), [](const query &a, const query &b)
{ return a.ans > b.ans; });
check(p);
}
sort(queries.begin(), queries.end(), [](const query &a, const query &b)
{ return a.index < b.index; });
for (int i = 0; i < q; ++i)
cout << queries[i].ans << '\n';
return 0;
}