#include <bits/stdc++.h>
using namespace std;
const int N = 300005;
vector<int> vec[N];
int n, m, l;
int w[N], lift[20][N];
struct DSU {
int papa[N], mx[N], sz[N];
void init() {
for (int i = 0; i < n; i ++) {
papa[i] = i;
mx[i] = i;
sz[i] = 1;
}
}
int real(int x) {
if (papa[x] == x)
return x;
return papa[x] = real(papa[x]);
}
void join(int x, int y) {
x = real(x);
y = real(y);
if (x == y) {
return;
}
if (sz[x] > sz[y]) {
swap(x, y);
}
if (w[mx[x]] > w[mx[y]]) {
mx[y] = mx[x];
}
papa[x] = y;
sz[y] += sz[x];
}
bool same_component(int x, int y) {
return real(x) == real(y);
}
int find_max(int x) {
return mx[real(x)];
}
};
int lol (int _l, int c) {
return m * _l + c;
}
struct Qry {
int time, x, y, i;
bool operator < (const Qry &oth) const {
return time < oth.time;
}
};
signed main() {
cin >> n >> m >> l;
//int _n = n, _m = m;
for (int i = 0; i < n; i ++) {
for (int j = 0; j < m; j ++) {
int x;
cin >> x;
w[lol(i, j)] = x;
}
}
for (int i = 0; i < n; i ++) {
for (int j = 1; j < m; j ++) {
vec[lol(i, j)].push_back(lol(i, j - 1));
vec[lol(i, j - 1)].push_back(lol(i, j));
}
}
for (int i = 1; i < n; i ++) {
for (int j = 0; j < m; j ++) {
vec[lol(i, j)].push_back(lol(i - 1, j));
vec[lol(i - 1, j)].push_back(lol(i, j));
}
}
n = n * m;
DSU ds;
ds.init();
vector<int> srt(n);
for (int i = 0; i < n; i ++) {
srt[i] = i;
}
sort(srt.begin(), srt.end(), [&] (int x, int y) { return w[x] < w[y]; });
int p = 0;
for (auto i : srt) {
while (p < (int)srt.size() && w[srt[p]] <= w[i] + l) {
for (auto j : vec[srt[p]]) {
if (w[srt[p]] >= w[j]) {
ds.join(srt[p], j);
}
}
p ++;
}
lift[0][i] = ds.find_max(i);
}
for (int i = 1; i < 20; i ++) {
for (int j = 0; j < n; j ++) {
lift[i][j] = lift[i - 1][lift[i - 1][j]];
}
}
int q;
cin >> q;
vector<Qry> queries;
while (q --) {
int a, b, c, d;
cin >> a >> b >> c >> d;
queries.push_back({0, lol(a - 1, b - 1), lol(c - 1, d - 1), (int)queries.size()});
}
for (int bit = 19; bit >= 0; bit --) {
vector<Qry> new_qry;
DSU ds_qry;
ds_qry.init();
for (auto i : queries) {
new_qry.push_back({w[lift[bit][i.x]] + l, lift[bit][i.x], i.y, i.i});
}
p = 0;
sort(new_qry.begin(), new_qry.end());
for (auto i : new_qry) {
while (p < (int)srt.size() && w[srt[p]] <= i.time) {
for (auto j : vec[srt[p]]) {
if (w[srt[p]] >= w[j]) {
ds_qry.join(srt[p], j);
}
}
p ++;
}
if (!ds_qry.same_component(i.x, i.y)) {
queries[i.i].time += (1 << bit);
queries[i.i].x = lift[bit][queries[i.i].x];
}
}
}
vector<Qry> new_qry;
ds.init();
for (auto i : queries) {
new_qry.push_back({w[i.x] + l, i.x, i.y, i.i});
}
p = 0;
sort(new_qry.begin(), new_qry.end());
for (auto i : new_qry) {
while (p < (int)srt.size() && w[srt[p]] <= i.time) {
for (auto j : vec[srt[p]]) {
if (w[srt[p]] >= w[j]) {
ds.join(srt[p], j);
}
}
p ++;
}
if (ds.same_component(i.x, i.y)) {
queries[i.i].time = -1;
}
}
for (auto i : queries) {
if (i.time == (1 << 20) - 1) {
cout << -1 << '\n';
} else {
cout << i.time + 2 << '\n';
}
}
}