#include <iostream>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <limits.h>
#include <algorithm>
#include <math.h>
#include <array>
#include <forward_list>
using namespace std;
int n, m;
bool onboard(int x, int y)
{
return 0 <= x && x < n && 0 <= y && y < m;
}
vector<vector<array<int, 2>>> p;
vector<vector<int>> s;
vector<vector<forward_list<array<int, 2>>>> elements;
array<int, 2> up(array<int, 2> node)
{
if (node == p[node[0]][node[1]]) return node;
else return p[node[0]][node[1]] = up(p[node[0]][node[1]]);
}
void unio(array<int, 2> a, array<int, 2> b)
{
if (up(a) == up(b)) return;
if (s[up(a)[0]][up(a)[1]] < s[up(b)[0]][up(b)[1]]) swap(a, b);
s[up(a)[0]][up(a)[1]] += s[up(b)[0]][up(b)[1]];
elements[up(a)[0]][up(a)[1]].splice_after(elements[up(a)[0]][up(a)[1]].begin(), elements[up(b)[0]][up(b)[1]]);
p[up(b)[0]][up(b)[1]] = up(a);
}
int main()
{
iostream::sync_with_stdio(0);
cin.tie(0);
int q, i, j;
cin >> n >> m >> q;
vector<vector<int>> hills(n, vector<int>(m));
for (i = 0; i < n; i++)
{
for (j = 0; j < m; j++)
{
cin >> hills[i][j];
}
}
vector<vector<vector<array<int, 3>>>> gq(n, vector<vector<array<int, 3>>>(m));
vector<array<int, 5>> queries(q);
for (i = 0; i < q; i++)
{
queries[i][0] = i;
cin >> queries[i][1] >> queries[i][2] >> queries[i][3] >> queries[i][4];
gq[--queries[i][1]][--queries[i][2]].push_back({ i, --queries[i][3], --queries[i][4] });
gq[queries[i][1]][queries[i][2]].push_back({ i, queries[i][3], queries[i][4] });
}
vector<int> ans(q, -1);
vector<array<int, 5>> edges;
edges.reserve(n * m);
vector<array<int, 2>> moves = { {1, 0}, {0, 1} }; //only up and right, not to find everything twice
for (i = 0; i < n; i++)
{
for (j = 0; j < m; j++)
{
for (auto mo : moves)
{
int x = i + mo[0], y = j + mo[1];
if (onboard(x, y))
{
edges.push_back({ max(hills[i][j], hills[x][y]), i, j, x, y });
}
}
}
}
sort(edges.begin(), edges.end());
s.resize(n, vector<int>(m, 1));
p.resize(n, vector<array<int, 2>>(m));
elements.resize(n, vector<forward_list<array<int, 2>>>(m));
for (i = 0; i < n; i++)
for (j = 0; j < m; j++)
{
p[i][j] = { i, j };
elements[i][j] = { {i, j} };
}
for (i = 0; i < edges.size(); i++)
{
array<int, 2> a = { edges[i][1], edges[i][2] }, b = { edges[i][3], edges[i][4] };
if (up(a) == up(b)) continue;
if (s[up(a)[0]][up(a)[1]] < s[up(b)[0]][up(b)[1]]) swap(a, b);
if (s[b[0]][b[1]] > 1000)
{
unio(a, b);
for (j = 0; j < q; j++)
{
if (ans[j] != -1) continue;
if (up({ queries[j][1], queries[j][2] }) == up({ queries[j][3], queries[j][4] }))
{
ans[j] = edges[i][0];
}
}
}
else
{
for (array<int, 2> e : elements[up(b)[0]][up(b)[1]])
{
for (array<int, 3> qe : gq[e[0]][e[1]])
{
if (ans[qe[0]] != -1) continue;
if (up(a) == up({ qe[1], qe[2] }))
{
ans[qe[0]] = edges[i][0];
}
}
}
unio(a, b);
}
}
for (i = 0; i < q; i++)
{
cout << ans[i] << '\n';
}
}