#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
FILE *fin = fopen( "matrice2.in", "r" ), *fout = fopen( "matrice2.out", "w" );
const int nmax = 310;
const int qmax = 20000;
const int valmax = 1e6;
const int inf = 1 << 30;
const int dl[ 4 ] = { -1, 0, 0, 1 };
const int dc[ 4 ] = { 0, -1, 1, 0 };
int n, nrq;
int v[ nmax * nmax + 1 ];
int tata[ nmax * nmax + 1 ], grad[ nmax * nmax + 1 ];
int ans[ qmax + 1 ];
vector< int > g[ nmax * nmax + 1 ];
struct keke{
int nr, val;
keke() {}
keke( int _nr, int _val ) {
nr = _nr, val = _val;
}
inline bool operator < ( const keke &a ) const {
return ( val > a.val );
}
};
vector< keke > s;
struct query{
int a, b;
} q[ qmax + 1 ];
struct check_query{
int ind, val;
bool ans;
inline bool operator < ( const check_query &x ) const {
return ( val > x.val );
}
} c[ qmax + 1 ];
inline int nr_asociat( int x, int y ) {
return (x - 1) * (n + 3) + y;
}
int find_tata( int x ) {
if ( x == tata[ x ] ) {
return x;
}
return ( tata[ x ] = find_tata( tata[ x ] ) );
}
void uneste( int x, int y ) {
int ta = find_tata( x ), tb = find_tata( y );
if ( ta == tb )
return ;
if ( grad[ ta ] < grad[ tb ] ) {
grad[ tb ] += grad[ ta ];
tata[ ta ] = tb;
} else {
grad[ ta ] += grad[ tb ];
tata[ tb ] = ta;
}
}
void unifica( int x, int val ) {
for( vector< int >::iterator it = g[ x ].begin(); it != g[ x ].end(); ++ it ) {
if ( v[ *it ] >= val ) {
uneste( x, *it );
}
}
}
void verif_tot() {
for( int i = 1; i <= n; ++ i ) {
for( int j = 1; j <= n; ++ j ) {
int x = nr_asociat( i, j );
tata[ x ] = x;
grad[ x ] = 1;
}
}
sort( c, c + nrq );
int j = 0;
for( int i = 0; i < nrq; ++ i ) {
while ( j < n * n && s[ j ].val >= c[ i ].val ) {
unifica( s[ j ].nr, c[ i ].val );
++ j;
}
int ta, tb;
ta = find_tata( q[ c[ i ].ind ].a );
tb = find_tata( q[ c[ i ].ind ].b );
c[ i ].ans = (ta == tb);
}
}
void cautare_binara_in_paralel() {
int n2;
for( n2 = 1; (n2 << 1) <= valmax; n2 <<= 1 ) {
}
for( int step = n2; step > 0; step >>= 1 ) {
for( int i = 0; i < nrq; ++ i ) {
c[ i ].ind = i;
if ( ans[ i ] + step > valmax ) {
c[ i ].val = ans[ i ];
} else {
c[ i ].val = ans[ i ] + step;
}
}
verif_tot();
for( int i = 0; i < nrq; ++ i ) {
if ( c[ i ].ans == 1 ) {
ans[ c[ i ].ind ] = c[ i ].val;
}
}
}
}
int main() {
fscanf( fin, "%d%d", &n, &nrq );
for( int i = 1; i <= n; ++ i ) {
for( int j = 1; j <= n; ++ j ) {
int x = nr_asociat( i, j );
fscanf( fin, "%d", &v[ x ] );
s.push_back( keke( x, v[ x ] ) );
for( int k = 0; k < 4; ++ k ) {
g[ x ].push_back( nr_asociat( i + dl[ k ], j + dc[ k ] ) );
}
}
}
for( int i = 0; i < nrq; ++ i ) {
int x1, y1, x2, y2;
fscanf( fin, "%d%d%d%d", &x1, &y1, &x2, &y2 );
q[ i ].a = nr_asociat( x1, y1 );
q[ i ].b = nr_asociat( x2, y2 );
}
for( int i = 0; i <= n + 1; ++ i ) {
v[ nr_asociat( i, 0 ) ] = v[ nr_asociat( 0, i ) ] = -inf;
v[ nr_asociat( i, n + 1 ) ] = v[ nr_asociat( n + 1, i ) ] = -inf;
}
sort( s.begin(), s.end() );
cautare_binara_in_paralel();
for( int i = 0; i < nrq; ++ i ) {
fprintf( fout, "%d\n", ans[ i ] );
}
fclose( fin );
fclose( fout );
return 0;
}