#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
struct pozitie {
int val, x,y;
pozitie ( int V, int X, int Y ) { val = V; x = X; y = Y; }
};
bool operator< ( const pozitie &a, const pozitie &b ) { return a.val > b.val; };
const int N_MAX = 301;
const int TOT = N_MAX*N_MAX+1;
const int logTOT = 17;
const int ND = 4;
const pozitie D[ND] = { pozitie(0,1,0), pozitie(0,0,1), pozitie(0,-1,0), pozitie(0,0,-1) };
const int INF = 0x3f3f3f3f;
int n,q;
int a[N_MAX][N_MAX];
vector<pozitie> v;
int used[N_MAX][N_MAX];
int tata[TOT], cost[TOT], h[TOT];
int root;
vector< pair<int,int> > G[TOT];
int level[TOT], anc[TOT][logTOT];
bool useddf[TOT];
int component ( int k ) {
if (tata[k] == k)
return k; else
return component(tata[k]);
}
void join ( int c1, int c2, int val ) {
if (h[c1] < h[c2])
c1 ^= c2 ^= c1 ^= c2;
tata[c2] = c1;
cost[c2] = val;
if (h[c1] < h[c2]+1)
h[c1] = h[c2]+1;
}
void get_component_tree() {
sort(v.begin(),v.end());
for (vector<pozitie>::iterator cur = v.begin(); cur != v.end(); ++cur) {
used[cur->x][cur->y] = cur - v.begin() + 1;
tata[used[cur->x][cur->y]] = used[cur->x][cur->y];
h[used[cur->x][cur->y]] = 1;
for (int i = 0; i < ND; ++i) {
int x = cur->x + D[i].x;
int y = cur->y + D[i].y;
int c1,c2;
if (0 <= x && x < n && 0 <= y && y < n && used[x][y] && (c1 = component(used[x][y])) != (c2 = component(used[cur->x][cur->y]))) {
join(c1, c2, cur->val);
}
}
}
}
void ancestors_df ( int k ) {
useddf[k] = true;
anc[k][0] = tata[k];
for (int i = 1; i < logTOT; ++i)
anc[k][i] = anc[anc[k][i-1]][i-1];
for (vector< pair<int,int> >::iterator next = G[k].begin(); next != G[k].end(); ++next) {
if (!useddf[next->first]) {
level[next->first] = level[k] + 1;
ancestors_df(next->first);
}
}
}
void get_ancestors() {
for (int i = 1; i <= n*n; ++i)
if (tata[i] == i)
root = i; else
G[tata[i]].push_back(make_pair(i,cost[i]));
ancestors_df(root);
}
inline int lsb ( int x ) { return ((x^(x-1)) + 1) >> 1; }
inline int log ( int x ) { return (x>>1) ? log(x>>1) + 1 : 0; }
int lca ( int a, int b ) {
if (level[a] > level[b]) {
a ^= b ^= a ^= b;
}
while (level[b] - level[a]) {
fprintf(stderr,"log(lsb(%d)) = %d\n",level[b]-level[a],log(lsb(level[b]-level[a])));
b = anc[b][log(lsb(level[b]-level[a]))];
}
if (a == b)
return a;
for (int step = logTOT-1; step >= 0; --step) {
if (anc[a][step] != anc[b][step]) {
a = anc[a][step];
b = anc[b][step];
}
}
a = anc[a][0];
b = anc[b][0];
return a;
}
int main() {
freopen("matrice2.in","rt",stdin);
freopen("matrice2.out","wt",stdout);
scanf("%d %d",&n,&q);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
scanf("%d",&a[i][j]);
v.push_back(pozitie(a[i][j],i,j));
}
}
get_component_tree();
get_ancestors();
for (int i = 0, a,b,c,d; i < q; ++i) {
scanf("%d %d %d %d",&a,&b,&c,&d);
--a; --b; --c; --d;
int v1 = used[a][b], v2 = used[c][d];
int x = lca(v1,v2);
int min = INF;
for (int cur = v1; cur != x; cur = tata[cur])
if (min > cost[cur])
min = cost[cur];
for (int cur = v2; cur != x; cur = tata[cur])
if (min > cost[cur])
min = cost[cur];
printf("%d\n",min);
}
return 0;
}