#include <fstream>
#include <algorithm>
#define nmax 200100
#define qmax 20100
#define mmax 310
#define nod(x,y) ((x<<9)|y)
#define First(x) (x>>9)
#define Second(x) (x&((1<<9)-1))
using namespace std;
struct punct{int Nod,Value;}Punct[nmax];
struct query{int A,B,Index,Answer;}Query[qmax];
int Dx[]={0,0,0,-1,1},Dy[]={0,-1,1,0,0};
int N,Nr,Q,Father[nmax],A[mmax][mmax];
bool comparePunctValue(punct X,punct Y) {
return X.Value>Y.Value;
}
bool compareQueryIndex(query X,query Y) {
return X.Index<Y.Index;
}
bool compareQueryAnswer(query X,query Y) {
return X.Answer>Y.Answer;
}
void Unite(int A,int B) {
Father[B]=A;
}
int Root(int Nod) {
if(Father[Nod]!=Nod)
return Father[Nod]=Root(Father[Nod]);
return Nod;
}
void Expand(int Nod,int Min) {
int i,v,w,X,Y;
v=Root(Nod);
for(i=1;i<=4;i++) {
X=First(Nod)+Dx[i];
Y=Second(Nod)+Dy[i];
if(A[X][Y]==-1 || A[X][Y]<Min)
continue;
w=Root(nod(X,Y));
if(v!=w)
Unite(v,w);
}
}
void initialiseForest() {
for(int i=1;i<=nod(N,N);i++)
Father[i]=i;
}
void bordare() {
for(int i=0;i<=N+1;i++)
A[i][0]=A[i][N+1]=A[0][i]=A[N+1][i]=-1;
}
void solve() {
int i,k,Step,Min;
Nr=N*N;
sort(Punct+1,Punct+Nr+1,comparePunctValue);
bordare();
for(Step=(1<<20);Step;Step>>=1) {
sort(Query+1,Query+Q+1,compareQueryAnswer);
initialiseForest();
for(i=k=1;i<=Q;i++) {
Min=Query[i].Answer+Step;
for(;k<=Nr && Punct[k].Value >= Min;k++)
Expand(Punct[k].Nod,Min);
if(Root(Query[i].A) == Root(Query[i].B))
Query[i].Answer = Min;
}
}
}
void read() {
int i,j,x,y;
ifstream in("matrice2.in");
in>>N>>Q;
for(i=1;i<=N;i++)
for(j=1;j<=N;j++) {
in>>A[i][j];
Punct[(i-1)*N+j].Nod=nod(i,j);
Punct[(i-1)*N+j].Value=A[i][j];
}
for(i=1;i<=Q;i++) {
in>>x>>y;
Query[i].A=nod(x,y);
in>>x>>y;
Query[i].B=nod(x,y);
Query[i].Index=i;
}
in.close();
}
void write() {
ofstream out("matrice2.out");
sort(Query+1,Query+Q+1,compareQueryIndex);
for(int i=1;i<=Q;i++)
out<<Query[i].Answer<<'\n';
out.close();
}
int main() {
read();
solve();
write();
return 0;
}