#include <bits/stdc++.h>
using namespace std;
ifstream fin("matrice2.in");
ofstream fout("matrice2.out");
const int NMAX = 300 + 10;
const int QMAX = 20000 + 10;
vector < pair < int , int > > cells;
pair < int , int > queries[QMAX];
int f[NMAX * NMAX] , b[NMAX * NMAX] , where[QMAX] , vmax[QMAX];
vector < int > lu , lr;
int N , Q , i , j , xu , xr , c , bx , by , ex , ey , nr , w;
const int dx[] = {-1 , 1 , 0 , 0};
const int dy[] = {0 , 0 , -1 , 1};
int wc(int i , int j)
{
return i * N + j + 1;
}
int iws(int x)
{
int rang;
(f[x] == x) ? rang = x : rang = iws(f[x]);
f[x] = rang;
return f[x];
}
void unite(int x , int y)
{
x = iws(x) , y = iws(y);
if (x == y) return;
f[x] = y;
}
void update(int cc)
{
cc -= 1;
int x = cc / N , y = cc % N;
cc += 1;
b[cc] = 0;
for (int k = 0 ; k < 4 ; ++k)
{
int tx = x + dx[k] , ty = y + dy[k];
if (0 <= tx && tx < N && 0 <= ty && ty < N)
{
int tc = wc(tx , ty);
if (!b[tc]) unite(tc , cc);
}
}
}
int main()
{
fin >> N >> Q;
for (i = 0 ; i < N ; ++i)
for (j = 0 ; j < N ; ++j)
{
fin >> c;
cells.push_back({c , wc(i , j)});
}
sort(cells.begin() , cells.end());
reverse(cells.begin() , cells.end());
for (i = 1 ; i <= Q ; ++i)
{
fin >> bx >> by >> ex >> ey;
bx -= 1 , by -= 1 , ex -= 1 , ey -= 1;
queries[i] = {wc(bx , by) , wc(ex , ey)};
where[i] = i;
}
nr = N * N;
for (c = (1 << 20) ; c >= 1 ; c >>= 1)
{
lu.clear() , lr.clear();
for (i = 1 ; i <= nr ; ++i)
f[i] = i , b[i] = 1;
for (i = 1 , j = 0 ; i <= Q ; ++i)
{
w = where[i];
while (j < nr && cells[j].first >= vmax[w] + c)
{
update(cells[j].second);
cout << cells[j].second << '\n';
j += 1;
}
if (iws(queries[w].first) == iws(queries[w].second))
{
vmax[w] += c;
lu.push_back(w);
} else lr.push_back(w);
}
xu = 0 , xr = 0 , i = 1;
while (xu < lu.size() && xr < lr.size())
if (vmax[lu[xu]] >= vmax[lr[xr]])
where[i++] = lu[xu++];
else where[i++] = lr[xr++];
while (xu < lu.size())
where[i++] = lu[xu++];
while (xr < lr.size())
where[i++] = lr[xr++];
}
for (i = 1 ; i <= Q ; ++i)
fout << vmax[i] << '\n';
return 0;
}