#include <algorithm>
#include <cassert>
#include <climits>
#include <cmath>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <vector>

using namespace std;

typedef int ll;
typedef unsigned long long ull;
typedef long double ld;
typedef vector<int> VI;
typedef vector<ll> VL;
typedef pair<int, int> ipair;
typedef tuple<int, int, int> ituple;

// const int MOD = (int)1e9 + 7;
// const double EPS = 1e-10;
#define PI acosl(-1)
#define MAX_N 9000005
    ll h, w, H, W, q;
    ll dat[MAX_N];

class SegmentTree2D {
protected:

  // ??¨????????????????????????????????¢??°
    virtual ll _func(ll a, ll b) = 0;

    ll query_h(int li, int lj, int ri, int rj, int si, int ti, int k) {
        if(ri <= si or ti <= li) return _getDefaultValue();
        if(li <= si and ti <= ri) return query_w(lj,rj,0,W,k,0);
        const int mi = (si+ti)/2;
        return _func(query_h(li,lj,ri,rj,si,mi,2*k+1), query_h(li,lj,ri,rj,mi,ti,2*k+2));
    }
    ll query_w(int lj, int rj, int sj, int tj, int i, int k) {
        if(rj <= sj or tj <= lj) return _getDefaultValue();
        if(lj <= sj and tj <= rj) return get(i, k);
        const int mj = (sj+tj)/2;
        return _func(query_w(lj,rj,sj,mj,i,2*k+1),query_w(lj,rj,mj,tj,i,2*k+2));
    }
public:
  // ??¨???????????????????????????????????????????????????????????????
    virtual ll _getDefaultValue() = 0;

    SegmentTree2D(){}

    ll get(int hh, int ww){
      // printf("get (%d, %d)[%lld] = %lld\n", hh, ww, hh*W+ww, dat[hh * W + ww]);
      return dat[hh * 2*W + ww];
    }

    void set(int hh, int ww, ll v){
      // printf("set (%d, %d)[%lld] = %lld\n", hh, ww, hh*W+ww, v);
      dat[hh * 2*W + ww] = v;
    }


    void init() {
        // H = W = 1;
        // while(H < (int)f.size()) H <<= 1;
        // while(W < (int)f[0].size()) W <<= 1;
        // dat.assign(2*H-1,VL(2*W-1, _getDefaultValue()));
        for (int i = 2*H-2; i > H-2; i--)
            for (int j = W-2; j >= 0; j--){
              set(i, j, _func(get(i, 2*j+1), get(i, 2*j+2)));

            }
        for (int i = H-2; i >= 0; i--)
            for (int j = 0; j < 2*W-1; j++){
                set(i, j,_func(get(2*i+1, j), get(2*i+2, j)));

            }
    }
    // [(li, ri), (lj, rj)]??????????????¨???????±???????
    ll query(int li, int lj, int ri, int rj) { return query_h(li,lj,ri + 1,rj + 1,0,H,0); }
};

class SegmentTree2DMin : public SegmentTree2D {
  using SegmentTree2D::SegmentTree2D;
protected:
  // ??¨????????????????????????????????¢??°
  ll _func(ll a, ll b){
    return min(a, b);
  }

public:
  // ??¨???????????????????????????????????????????????????????????????
  ll _getDefaultValue(){
    return INT_MAX;
  }
};

void exec(){

  int tmp, r1, r2, c1, c2;
    SegmentTree2DMin st2 = SegmentTree2DMin();
    for (int i = 0; i < MAX_N; i++){
      dat[i] = st2._getDefaultValue();
    }
    for (int i = 0; i < h; i++)
    for (int j = 0; j < w; j++){
      scanf("%d", &tmp);
      st2.set(i+H-1, j+W-1, tmp);

    }
    st2.init();

    for (int i = 0; i < q; i++){
      scanf("%d%d%d%d", &r1, &c1, &r2, &c2);
      printf("%d\n", st2.query(r1, c1, r2, c2));
    }
}

void solve(){
  while (scanf("%d%d%d", &h, &w, &q)!=EOF){
    if (h + w + q <= 0){
      break;
    }
    H = W = 1;
    while(H < h) H <<= 1;
    while(W < w) W <<= 1;
    exec();
  }
}

int main(){
  solve();
  return 0;
}

Measured memory_bytes: 38396