#include <bits/stdc++.h>
#define MAX_N 300
#define MAX_Q 20000
#define MAX_DIR 4
using namespace std;
FILE *f, *g;
int n, q;
struct nrul
{
int x, cod;
};
nrul nr[MAX_N * MAX_N + 1];
struct elem
{
int x, y, i, rez;
};
elem v[MAX_Q + 1];
struct query
{
int nr, i;
int ok;
};
query que[MAX_Q + 1];
struct cmpNR
{
bool operator () (const nrul &a, const nrul &b) const
{
return a.x > b.x;
}
};
struct cmpQ
{
bool operator () (const query &a, const query &b) const
{
return a.nr > b.nr;
}
};
const int dl[] = {-1, 1, 0, 0};
const int dc[] = {0, 0, -1, 1};
int a[MAX_N * MAX_N + 1];
int lin[MAX_N * MAX_N + 1];
int comp[MAX_N * MAX_N + 1];
int h[MAX_N * MAX_N + 1];
struct cmpI
{
bool operator () (const elem &a, const elem &b) const
{
return a.i < b.i;
}
};
int getCod(int i, int j)
{
return (i - 1) * n + j;
}
void readFile()
{
f = fopen("matrice2.in", "r");
fscanf(f, "%d", &n);
fscanf(f, "%d", &q);
int i, j;
for(i = 1; i <= n; i ++)
{
for(j = 1; j <= n; j ++)
{
int cod = getCod(i, j);
lin[cod] = i;
fscanf(f, "%d", &a[cod]);
}
}
int l, c;
for(i = 1; i <= q; i ++)
{
fscanf(f, "%d%d", &l, &c);
v[i].x = getCod(l, c);
fscanf(f, "%d%d", &l, &c);
v[i].y = getCod(l, c);
v[i].i = i;
}
fclose(f);
}
void init0()
{
int i, j;
for(i = 1; i <= n; i ++)
{
for(j = 1; j <= n; j ++)
{
int cod = getCod(i, j);
comp[cod] = cod;
h[cod] = 1;
}
}
}
void unestele(int a, int b)
{
// cout << "UNIM COD " << a << " " << b << "\n";
if(h[a] >= h[b])
{
h[a] += (h[a] == h[b]);
comp[b] = a;
}
else
{
comp[a] = b;
}
}
bool inMat(int l, int c)
{
return l >= 1 && l <= n && c >= 1 && c <= n;
}
int getComp(int a)
{
if(comp[a] == a)
return a;
return comp[a] = getComp(comp[a]);
}
void uneste(int cod)
{
// cout << "INTRA\n";
int i = lin[cod];
int j = cod - (i - 1) * n;
// cout << "SUNTEM PE " << cod << " " << i << " " << j << "\n";
int dir;
for(dir = 0; dir < MAX_DIR; dir ++)
{
// cout << "DIR " << dir << "\n";
int nl = i + dl[dir];
int nc = j + dc[dir];
// cout << "POS " << nl << " " << nc << "\n";
if(inMat(nl, nc))
{
//cout << "E BINE \n";
int nx = getCod(nl, nc);
int ca = getComp(cod);
int cb = getComp(nx);
if(a[nx] >= a[cod] && ca != cb)
unestele(ca, cb);
}
}
}
int unite(int a, int b)
{
int ca = getComp(a);
int cb = getComp(b);
if(ca == cb)
return 1;
return 0;
}
void cautBin()
{
int nn = n * n;
int pas = 1 << 20;
while(pas != 0)
{
init0();
int k = 0;
for(int i = 1; i <= q; i ++)
que[++ k] = {v[i].rez + pas, i, 0};
sort(que + 1, que + q + 1, cmpQ());
int i = 1;
int j = 1;
while(i <= nn && j <= q)
{
if(nr[i].x >= que[j].nr)
{
uneste(nr[i].cod);
i ++;
}
else
{
que[j].ok = unite(v[que[j].i].x, v[que[j].i].y);
j ++;
}
}
while(j <= q)
{
que[j].ok = unite(v[que[j].i].x, v[que[j].i].y);
j ++;
}
for(i = 1; i <= q; i ++)
{
if(que[i].ok)
v[que[i].i].rez = que[i].nr;
}
pas >>= 1;
}
}
void getNr()
{
int k = 0;
int i, j;
for(i = 1; i <= n; i ++)
{
for(j = 1; j <= n; j ++)
{
int cod = getCod(i, j);
nr[++ k] = {a[cod], cod};
}
}
sort(nr + 1, nr + n * n + 1, cmpNR());
}
void solve()
{
getNr();
cautBin();
sort(v + 1, v + q + 1, cmpI());
}
void printFile()
{
g = fopen("matrice2.out", "w");
int i;
for(i = 1; i <= q; i ++)
fprintf(g, "%d\n", v[i].rez);
fclose(g);
}
int main()
{
readFile();
solve();
printFile();
return 0;
}