#include <cstdio>
#include <cassert>
#include <vector>
#include <set>
#include <map>
#include <algorithm>
#include <utility>
using namespace std;
#define FORIT(it, v) for (typeof((v).begin()) it = (v).begin(); it != (v).end(); ++it)
const int MAXN = 303;
const int MAXQ = 20013;
const int dx[4] = { -1, 0, 1, 0 };
const int dy[4] = { 0, 1, 0, -1 };
struct query {
int x1, y1, x2, y2;
};
int A[MAXN][MAXN], N, Q;
query queries[MAXQ];
int sol[MAXQ];
vector< pair<int, int> > B;
multimap<int, int> mm;
inline bool inside(int x, int y) {
return (1 <= x && x <= N && 1 <= y && y <= N);
}
// Disjoint sets
int pi[MAXN*MAXN], rank[MAXN*MAXN];
int member[MAXN][MAXN], nr_members;
inline void make_set(int x) {
pi[x] = x;
rank[x] = 0;
}
int find(int x) {
if (pi[x] != x)
pi[x] = find(pi[x]);
return pi[x];
}
void merge(int x, int y) {
x = find(x);
y = find(y);
if (x == y) return;
if (rank[x] < rank[y])
pi[x] = y;
else if (rank[x] > rank[y])
pi[y] = x;
else {
pi[x] = y;
rank[y]++;
}
}
void read() {
assert( scanf("%d %d", &N, &Q) == 2 );
for (int i = 1; i <= N; i++)
for (int j = 1; j <= N; j++)
assert( scanf("%d", &A[i][j]) == 1);
for (int i = 0; i < Q; i++) {
query q;
assert( scanf("%d %d %d %d", &q.x1, &q.y1, &q.x2, &q.y2) == 4 );
queries[i] = q;
}
}
bool cmp(pair<int, int> i, pair<int, int> j) {
return (A[i.first][i.second] > A[j.first][j.second]);
}
inline bool issatisfied(query q) {
int a, b;
a = member[q.x1][q.y1];
b = member[q.x2][q.y2];
if (!a || !b) return false;
return ( find(a) == find(b) );
}
void step(int delta) {
nr_members = 1;
for (int i = 1; i <= N; i++)
for (int j = 1; j <= N; j++)
member[i][j] = 0;
// Sort queries by their sol.
for (int i = 0; i < Q; i++)
mm.insert( make_pair(sol[i] + delta, i) );
multimap<int,int>::iterator mmit = mm.begin();
int x, y, nx, ny, k;
for (int i = 0; i < (int)B.size();) {
x = B[i].first;
y = B[i].second;
member[x][y] = nr_members;
make_set(nr_members);
nr_members++;
for (k = 0; k < 4; k++) {
nx = x + dx[k];
ny = y + dy[k];
if ( inside(nx, ny) && member[nx][ny] != 0 ) {
merge( member[x][y], member[nx][ny] );
}
}
++i;
for (; mmit != mm.end() && mmit->first == i; ++mmit) {
//printf("Checking query #%d (val=%d | %d) when i = %d\n",
// mmit->second, mmit->first, A[x][y], i);
if ( !issatisfied(queries[mmit->second]) )
sol[mmit->second] += delta;
}
}
mm.clear();
//printf(" Sol (delta=%3d): ", delta);
//for (int i = 0; i < Q; i++) printf("%2d ", sol[i]);
//printf("\n");
}
void solve() {
for (int i = 1; i <= N; i++)
for (int j = 1; j <= N; j++)
B.push_back(make_pair(i, j));
sort(B.begin(), B.end(), cmp);
//for (int i = 0; i < (int)B.size(); ++i)
// printf("B#%2d: %d\n", i, A[B[i].first][B[i].second]);
int delta;
for (delta = 1; delta < (int)B.size(); delta <<= 1);
for (; delta; delta >>= 1)
step(delta);
pair<int, int> p;
for (int i = 0; i < Q; i++) {
p = B[sol[i]];
printf("%d\n", A[p.first][p.second] );
}
}
int main() {
assert( freopen("matrice2.in", "r", stdin) );
assert( freopen("matrice2.out", "w", stdout) );
read();
solve();
return 0;
}