#define _CRT_SECURE_NO_WARNINGS
//#define _GLIBCXX_DEBUG
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef pair<int,int> pii;
#define all(c) (c).begin(), (c).end()
#define loop(i,a,b) for(ll i=a; i<ll(b); i++)
#define rep(i,b) loop(i,0,b)
#define pb push_back
#define eb emplace_back
#define mp make_pair
#define mt make_tuple
template<class T> istream & operator>>(istream & is, vector<T> &);
template<class T> ostream & operator<<(ostream & os, vector<T> const &);
template<int n, class...T> typename enable_if<(n>=sizeof...(T))>::type _ot(ostream &, tuple<T...> const &){}
template<int n, class...T> typename enable_if<(n< sizeof...(T))>::type _ot(ostream & os, tuple<T...> const & t){ os << (n==0?"":" ") << get<n>(t); _ot<n+1>(os, t); }
template<class...T> ostream & operator<<(ostream & os, tuple<T...> const & t){ _ot<0>(os, t); return os; }
template<int n, class...T> typename enable_if<(n>=sizeof...(T))>::type _it(istream &, tuple<T...> &){}
template<int n, class...T> typename enable_if<(n< sizeof...(T))>::type _it(istream & is, tuple<T...> & t){ is >> get<n>(t); _it<n+1>(is, t); }
template<class...T> istream & operator>>(istream & is, tuple<T...> & t){ _it<0>(is, t); return is; }
template<class T, class U> istream & operator<<(istream & is, pair<T,U> & p){ return is >> p.first >> p.second; }
template<class T, class U> ostream & operator<<(ostream & os, pair<T,U> const & p){ return os << "(" << p.first << ", " << p.second << ") "; }
template<class T> istream & operator>>(istream & is, vector<T> & v){ rep(i,v.size()) is >> v[i]; return is; }
template<class T> ostream & operator<<(ostream & os, vector<T> const & v){ rep(i,v.size()) os << v[i] << (i+1==(int)v.size()?"":" "); return os; }
#ifdef DEBUG
#define dump(...) (cerr<<#__VA_ARGS__<<" = "<<mt(__VA_ARGS__)<<" ["<<__LINE__<<"]"<<endl)
#else
#define dump(...)
#endif

typedef unsigned int dat_t;
dat_t const inf = (1LL<<32)-1;

int const MAX_SIZE = 250000*40;
struct Pool {
    static dat_t dat[MAX_SIZE];
    static int size;
    static dat_t * fetch(int len){
        dat_t * res = dat + size;
        size+=len;
        return res;
    }
    static void reset(){
        size = 0;
    }
};

int Pool::size = 0;
dat_t Pool::dat[MAX_SIZE];

Pool pool;

struct SegTree {
    dat_t * dat; int n;
    explicit SegTree(int n_){
        int k = 1;
        while(k < n_) k<<=1;
        n = k;
        dat = pool.fetch(n*2);
        fill(dat, dat+k*2, inf);
    }
    explicit SegTree(const SegTree& s){
        n = s.n;
        dat = pool.fetch(n*2);
        rep(i,n*2) dat[i] = s.dat[i];
    }
    void set(int x, dat_t val){
        int i = n + x; // leaf
        dat[i] = val;
        while(i != 1){ // 1 is root
            dat[i>>1] = min(dat[i],dat[i^1]);
            i>>=1;
        }
    }
    dat_t get(int a, int b, int k=1, int l=0, int r=-1) const {
        if(r == -1) r = n;
        if(r <= a || b <= l) return inf;
        if(a <= l && r <= b){
            auto res = dat[k];
            return res;
        }
        dat_t v1 = get(a, b, k<<1,   l,       (l+r)/2 );
        dat_t v2 = get(a, b, k<<1|1, (l+r)/2, r       );
        return min(v1,v2);
    }
};

struct SegTree2D {
    vector<SegTree> dat; int n;
    explicit SegTree2D(int h, int w){
        int k = 1;
        while(k < h) k<<=1;
        n = k;
        dat.assign(k*2, SegTree(w));
    }
    void set(int x, int y, dat_t val){
        int i = n + y; // leaf
        dat[i].set(x, val);
        while(i != 1){ // 1 is root
            dat[i>>1].set(x, min(dat[i].get(x,x+1), dat[i^1].get(x,x+1)));
            i>>=1;
        }
    }
    dat_t get(int x1, int x2, int y1, int y2, int k=1, int l=0, int r=-1) const {
        if(r == -1) r = n;
        if(r <= y1 || y2 <= l) return inf;
        if(y1 <= l && r <= y2){
            auto res = dat[k].get(x1,x2);
            return res;
        }
        dat_t v1 = get(x1, x2, y1, y2, k<<1,   l,       (l+r)/2 );
        dat_t v2 = get(x1, x2, y1, y2, k<<1|1, (l+r)/2, r       );
        return min(v1,v2);
    }
};

int r,c,q;

int main(){
#ifdef LOCAL
    freopen("in","r",stdin);
#endif
    while(cin>>r>>c>>q && r){
        SegTree2D tree(r,c);
        rep(i,r)rep(j,c){
            dat_t x;
            cin >> x;
            tree.set(j,i,x);
        }
        rep(i,q){
            int x1,x2,y1,y2;
            cin >> y1>>x1>>y2>>x2;
            y2++; x2++;
            cout << tree.get(x1,x2,y1,y2) << endl;
        }
        pool.reset();
    }
}

Measured memory_bytes: 52232