#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#define INF 2140000000
#define MaxN 305
#define MaxQ 200000
#define pi 3.1415926535897932384626433832795
using namespace std;
FILE *IN,*OUT;
int N,Q,Last[MaxQ],Max=0,pos=0;
struct spec
{
int fx,fy,value;
}Mat[MaxN][MaxN];
struct spec2
{
int value,x,y;
}l[MaxN*MaxN];
struct query
{
int x1,y1,x2,y2,pos;
};
vector <query> Quest;
bool cond(spec2 a,spec2 b)
{
return a.value>b.value;
}
queue <pair<pair<int,int>,vector<query> > > Queue;
void Reinitialize()
{
pos=0;
for(int i=1;i<=N;i++)
for(int j=1;j<=N;j++)
Mat[i][j].fx=i,Mat[i][j].fy=j;
}
pair<int,int>find(int x,int y)
{
pair<int,int>orig;
orig.first=x,orig.second=y;
while(Mat[x][y].fx!=x||Mat[x][y].fy!=y)
{
int ax=Mat[x][y].fx,ay=Mat[x][y].fy;
x=ax,y=ay;
}
while(orig.first!=x||orig.second!=y)
{
int ax=Mat[orig.first][orig.second].fx,ay=Mat[orig.first][orig.second].fy;
Mat[orig.first][orig.second].fx=x;
Mat[orig.first][orig.second].fy=y;
orig.first=ax,orig.second=ay;
}
return make_pair(x,y);
}
void Add(spec2 point)
{
int X=point.x,Y=point.y,V=point.value;
if(Mat[X][Y].fx!=X||Mat[X][Y].fy!=Y)
return;
if(X>1&&Mat[X-1][Y].value>=V)
{
pair<int,int> f=find(X-1,Y);
Mat[f.first][f.second].fx=X;
Mat[f.first][f.second].fy=Y;
}
if(Y>1&&Mat[X][Y-1].value>=V)
{
pair<int,int> f=find(X,Y-1);
Mat[f.first][f.second].fx=X;
Mat[f.first][f.second].fy=Y;
}
if(X<N&&Mat[X+1][Y].value>=V)
{
pair<int,int> f=find(X+1,Y);
Mat[f.first][f.second].fx=X;
Mat[f.first][f.second].fy=Y;
}
if(Y<N&&Mat[X][Y+1].value>=V)
{
pair<int,int> f=find(X,Y+1);
Mat[f.first][f.second].fx=X;
Mat[f.first][f.second].fy=Y;
}
}
int main() {
IN=fopen("matrice2.in","r");
OUT=fopen("matrice2.out","w");
fscanf(IN,"%d%d",&N,&Q);
for(int i=1;i<=N;i++)
for(int j=1;j<=N;j++)
{
fscanf(IN,"%d",&Mat[i][j].value);
Mat[i][j].fx=i;
Mat[i][j].fy=j;
l[(i-1)*N+j].value=Mat[i][j].value;
l[(i-1)*N+j].x=i;
l[(i-1)*N+j].y=j;
Max=max(Max,Mat[i][j].value);
}
sort(l+1,l+1+N*N,cond);
for(int i=1;i<=Q;i++)
{
query aux;
fscanf(IN,"%d%d%d%d",&aux.x1,&aux.y1,&aux.x2,&aux.y2);
aux.pos=i;
Quest.push_back(aux);
}
l[0].value=INF;
Queue.push(make_pair(make_pair(Max,0),Quest));
while(!Queue.empty())
{
int L=Queue.front().first.first;
int R=Queue.front().first.second;
int Mid=(R+L)>>1;
vector<query> left,right;
if(l[pos].value<Mid)
Reinitialize();
while(l[pos+1].value>Mid)
Add(l[++pos]);
for(int i=0;i<Queue.front().second.size();i++)
{
query aux=Queue.front().second[i];
if(find(aux.x1,aux.y1)==find(aux.x2,aux.y2))
left.push_back(aux);
else right.push_back(aux);
}
if(L-R<=1)
{
for(int i=0;i<left.size();i++)
Last[left[i].pos]=L;
for(int i=0;i<right.size();i++)
Last[right[i].pos]=R;
}
else
{
if(!left.empty())
Queue.push(make_pair(make_pair(L,Mid+1),left));
if(!right.empty())
Queue.push(make_pair(make_pair(Mid,R),right));
}
Queue.pop();
}
for(int i=1;i<=Q;i++)
fprintf(OUT,"%d\n",Last[i]);
return 0;
}