#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
typedef long long ll;
using namespace __gnu_pbds;
using namespace std;
template <typename T>
using ordered_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
struct Query {
ll a, b, c, d, f, s;
};
struct DSU {
vector<ll> rep, sajz;
vector<pair<ll, ll>> mx;
DSU(ll n) {
rep.resize(n+1);
sajz.assign(n+1,1);
mx.assign(n+1, {});
for(ll i=0; i<=n; ++i) rep[i] = i;
}
void ustaw(ll x, ll val) {
mx[x] = {val, x};
}
ll Find(ll v) {
return rep[v] == v ? v : rep[v] = Find(rep[v]);
}
bool Union(ll a, ll b) {
a=Find(a);
b=Find(b);
if(a==b) return 0;
if(sajz[b] > sajz[a]) swap(a,b);
rep[b] = a;
sajz[a] += sajz[b];
mx[a] = max(mx[a], mx[b]);
return 1;
}
};
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
ll h,w,L;
cin >> h >> w >> L;
vector<vector<ll>> T(h, vector<ll>(w));
for(ll i=0; i<h; ++i) {
for(ll j=0; j<w; ++j) cin >> T[i][j];
}
auto trans = [&](ll a, ll b) { return a*w + b; };
auto tb = [&](ll x) { return make_pair(x/w, x%w); };
ll q; cin >> q;
vector<Query> zap(q);
for(ll i=0; i<q; ++i) {
cin >> zap[i].a >> zap[i].b >> zap[i].c >> zap[i].d;
zap[i].a--; zap[i].b--; zap[i].c--; zap[i].d--;
zap[i].f = trans(zap[i].a, zap[i].b);
zap[i].s = trans(zap[i].c, zap[i].d);
}
ll n = w*h + 10;
DSU mst(n), dsu(n), tree(n);
map<ll, vector<ll>> mapa;
for(ll i=0; i<h; ++i) {
for(ll j=0; j<w; ++j) {
mapa[T[i][j]].push_back(trans(i,j));
}
}
auto proba = [&](ll x, ll a, ll b, DSU &D) {
auto[c,d] = tb(x);
if(a < 0 || a >= h || b < 0 || b >= w || T[a][b] > T[c][d]) return;
D.Union(x, trans(a,b));
};
auto connect = [&](ll x, DSU &D) {
auto[a,b] = tb(x);
proba(x, a+1, b, D);
proba(x, a-1, b, D);
proba(x, a, b+1, D);
proba(x, a, b-1, D);
};
for(auto[t, vec] : mapa) {
for(auto x : vec) connect(x, mst);
map<ll, ll> prio;
for(auto x : vec) {
if(prio.find(mst.Find(x)) == prio.end()) prio[mst.Find(x)] = x;
else dsu.Union(x, prio[mst.Find(x)]);
}
}
vector<ll> edge(n);
vector<ll> heights;
for(ll i=0; i<h; ++i) for(ll j=0; j<w; ++j) heights.push_back(T[i][j]);
sort(heights.begin(), heights.end());
map<ll, vector<ll>> check;
DSU mxdsu(n);
for(ll i=0; i<h; ++i) for(ll j=0; j<w; ++j) {
mxdsu.ustaw(trans(i,j), T[i][j]);
auto it = upper_bound(heights.begin(), heights.end(), T[i][j] + L);
if(it==heights.end()) edge[trans(i,j)] = dsu.Find(mapa.rbegin()->second[0]);
else check[*it].push_back(trans(i,j));
}
for(auto[t, vec] : mapa) {
for(auto x : check[t]) edge[x] = mxdsu.mx[mxdsu.Find(x)].second;
for(auto x : vec) connect(x, mxdsu);
}
for(auto &x : edge) x = dsu.Find(x);
for(ll i=0; i<h; ++i) for(ll j=0; j<w; ++j) {
// auto[a,b] = tb(dsu.Find(trans(i,j)));
// cout << "(" << i << " " << j << "): " << a << " " << b << "\n";
// auto[c,d] = tb(edge[trans(i,j)]);
// cout << "(" << i << " " << j << "): " << c << " " << d << "\n";
}
;vector<ll> depth(n);
for(auto it=mapa.rbegin(); it!=mapa.rend(); ++it) {
for(auto x : it->second) {
if(dsu.Find(x) != x) continue;
tree.Union(x, edge[x]);
depth[x] = depth[edge[x]] + 1;
}
}
vector<ll> lo(q,0), hi(q, (ll)mapa.size() - 1), mid(q);
while(1) {
ll ile = 0;
vector<vector<ll>> sweep(mapa.size());
for(ll x=0; x<q; ++x) {
if(lo[x] < hi[x]) {
ile++;
mid[x] = (lo[x] + hi[x]) / 2;
sweep[mid[x]].push_back(x);
}
}
if(!ile) break;
DSU dsu2(n);
for(ll i=0; i<h; ++i) for(ll j=0; j<w; ++j) dsu2.ustaw(trans(i,j), T[i][j]);
ll idx = 0;
for(auto[t, vec] : mapa) {
for(auto x : vec) connect(x, dsu2);
for(auto x : sweep[idx]) {
if(dsu2.Find(zap[x].f) == dsu2.Find(zap[x].s)) hi[x] = mid[x];
else lo[x] = mid[x] + 1;
}
idx++;
}
}
vector<vector<ll>> sweep(mapa.size());
vector<ll> target(q);
for(ll x=0; x<q; ++x) sweep[lo[x]].push_back(x);
DSU dsu2(n);
for(ll i=0; i<h; ++i) for(ll j=0; j<w; ++j) dsu2.ustaw(trans(i,j), T[i][j]);
ll idx = 0;
for(auto[t, vec] : mapa) {
for(auto x : vec) connect(x, dsu2);
for(auto i : sweep[idx]) target[i] = dsu.Find(dsu2.mx[dsu2.Find(zap[i].f)].second);
idx++;
}
for(ll i=0; i<q; ++i) {
zap[i].f = dsu.Find(zap[i].f);
if(tree.Find(zap[i].f) != tree.Find(target[i])) cout << "-1\n";
else cout << max(0LL, depth[zap[i].f] - depth[target[i]]) << "\n";
}
return 0;
}