#include <cstdio>
#include <queue>
using namespace std;
const int nmx = 302;
const int p1[] = {0,0,1,-1}, p2[] = {1,-1,0,0};
int n,queries,mat[nmx][nmx],maxim[nmx][nmx];
priority_queue <pair<int,pair<int,int> > > q;
void citire()
{
scanf("%d %d", &n, &queries);
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j)
scanf("%d", &mat[i][j]);
}
bool apartine(int x, int y)
{
return x > 0 && x <= n && y > 0 && y <= n;
}
void reset_maxim()
{
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j)
maxim[i][j] = 0;
}
void dijkstra(int x1, int y1, int x2, int y2)
{
while(not q.empty())
q.pop();
reset_maxim();
maxim[x1][y1] = mat[x1][y1];
for(int i = 0; i < 4; ++i)
if(apartine(x1+p1[i],y1+p2[i]))
{
maxim[x1+p1[i]][y1+p2[i]] = min(maxim[x1][y1],mat[x1+p1[i]][y1+p2[i]]);
q.push({maxim[x1+p1[i]][y1+p2[i]],{x1+p1[i],y1+p2[i]}});
}
int x,y,cost;
while(not q.empty())
{
cost = q.top().first;
x = q.top().second.first;
y = q.top().second.second;
q.pop();
//maxim[x][y] = cost;
if(x == x2 && y == y2)
{
printf("%d\n", cost);
break;
}
for(int i = 0; i < 4; ++i)
if(apartine(x+p1[i],y+p2[i]) && not maxim[x+p1[i]][y+p2[i]])
{
maxim[x+p1[i]][y+p2[i]] = min(maxim[x][y],mat[x+p1[i]][y+p2[i]]);
q.push({maxim[x+p1[i]][y+p2[i]],{x+p1[i],y+p2[i]}});
}
}
}
void tests()
{
while(queries--)
{
int x1,x2,y1,y2;
scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
dijkstra(x1,y1,x2,y2);
}
}
int main()
{
freopen("matrice2.in", "r", stdin);
freopen("matrice2.out", "w", stdout);
citire();
tests();
return 0;
}