// Original C++ solution (slower):
#include <stdio.h>

#include <string.h>

#include <algorithm>



using namespace std;



typedef long long LL;



#define INF 0x7fffffff

#define MAX 1048576

#define MAXN 65535

#define MAXLg 16

#define MAXQ 20000



int A[MAX],Log[MAXN + 1],tableMin[MAXN][MAXLg];



void makeRMinQ(int *a,int s,int t){

	int n = t - s;

	for (int i = s; i < t; ++i) tableMin[i - s][0] = a[i];

	for (int j = 1; (1 << j) <= n; ++j)

		for (int i = s; i + (1 << j) <= t; ++i)

			tableMin[i - s][j] = min(tableMin[i - s][j - 1], tableMin[i - s + (1 << (j - 1))][j - 1]);

}



int QueryMin(int x,int y){

	int p = Log[y - x + 1];

	return min(tableMin[x][p],tableMin[y - (1 << p) + 1][p]);

}



struct query{

    int x1, y1;

    int x2, y2;

}fQ[MAXQ];



int Res[MAXQ];



int main() {

	for (int i = 0, x = 0, cd = 2; i <= MAXN; ++x, cd <<= 1)

		while (i <= MAXN && i < cd)

		    Log[++i] = x;

	int R, C, Q;

	while(scanf("%d%d%d",&R,&C,&Q), R){

        if (R <= C){

            for (int i = 0; i < R; ++i)

                for (int j = 0; j < C; ++j)

                    scanf("%d", &A[i * C + j]);

            for (int q = 0; q < Q; ++q)

                scanf("%d%d%d%d", &fQ[q].x1, &fQ[q].y1, &fQ[q].x2, &fQ[q].y2);

        }else{

            for (int i = 0; i < R; ++i)

                for (int j = 0; j < C; ++j)

                    scanf("%d", &A[j * R + i]);

            swap(R, C);

            for (int q = 0; q < Q; ++q){

                scanf("%d%d%d%d", &fQ[q].x1, &fQ[q].y1, &fQ[q].x2, &fQ[q].y2);

                swap(fQ[q].x1, fQ[q].y1);

                swap(fQ[q].x2, fQ[q].y2);

            }

        }

        for (int q = 0;q < Q; ++q)

            Res[q] = INF;

        int fC = (C-1) / MAXN+1;

        for (int i = 0; i < R; ++i){

            for (int j = 0, k = 0; j < fC; ++j){

                int nk = min(C, k + MAXN);

                makeRMinQ(A, i * C + k, i * C + nk);

                for (int q = 0; q < Q; ++q){

                    if (i < fQ[q].x1 || fQ[q].x2 < i)

                        continue;

                    int cs = max(fQ[q].y1,k);

                    int ct = min(fQ[q].y2,nk - 1);

                    if (cs > ct) continue;

                    Res[q] = min(Res[q],QueryMin(cs - k,ct - k));

                }

                k = nk;

            }

        }

        for (int q = 0; q < Q; ++q)

            printf("%d\n", Res[q]);

    }

    return 0;

}

// Optimized solution to the same problem (faster):
#include <cstdio>

#include <cstdlib>

#include <cstring>

#include <algorithm>



using namespace std;



const int maxn=1e6+5;



int tree[16*maxn],n,m,f[maxn],q;

int r1,r2,c1,c2;



void ini0(int pos1,int pos2,int begin,int end,int r)

{

    if(begin==end)tree[pos1*m*4+pos2]=f[r*m+begin];

    else

    {

        int mid=(begin+end)>>1;

        ini0(pos1,pos2<<1,begin,mid,r);

        ini0(pos1,(pos2<<1)|1,mid+1,end,r);

        if(tree[pos1*m*4+(pos2<<1)]<tree[pos1*m*4+((pos2<<1)|1)])tree[pos1*m*4+pos2]=tree[pos1*m*4+(pos2<<1)];

        else tree[pos1*m*4+pos2]=tree[pos1*m*4+((pos2<<1)|1)];

    }

}



void ini1(int pos1,int pos2,int begin,int end)

{

    if(tree[(pos1<<1)*m*4+pos2]<tree[((pos1<<1)|1)*m*4+pos2])tree[pos1*m*4+pos2]=tree[(pos1<<1)*m*4+pos2];

    else tree[pos1*m*4+pos2]=tree[((pos1<<1)|1)*m*4+pos2];

    if(begin!=end)

    {

        int mid=(begin+end)>>1;

        ini1(pos1,pos2<<1,begin,mid);

        ini1(pos1,(pos2<<1)|1,mid+1,end);

    }

}



void ini(int pos,int begin,int end)

{

    if(begin==end)ini0(pos,1,0,m-1,begin);

    else

    {

        int mid=(begin+end)>>1;

        ini(pos<<1,begin,mid);

        ini((pos<<1)|1,mid+1,end);

        ini1(pos,1,0,m-1);

    }

}



int find2(int pos1,int pos2,int begin,int end)

{

    if(c1<=begin && end<=c2)return tree[pos1*4*m+pos2];

    else

    {

        int mid=(begin+end)>>1;

        if(c2<=mid)return find2(pos1,pos2<<1,begin,mid);

        else if(c1>mid)return find2(pos1,(pos2<<1)|1,mid+1,end);

        else return min(find2(pos1,pos2<<1,begin,mid),find2(pos1,(pos2<<1)|1,mid+1,end));

    }

}



int find(int pos,int begin,int end)

{

    if(r1<=begin && end<=r2)return find2(pos,1,0,m-1);

    else

    {

        int mid=(begin+end)>>1;

        if(r2<=mid)return find(pos<<1,begin,mid);

        else if(r1>mid)return find((pos<<1)|1,mid+1,end);

        else return min(find(pos<<1,begin,mid),find((pos<<1)|1,mid+1,end));

    }

}



int main()

{

    while(scanf("%d%d%d",&n,&m,&q)==3 && (n||m||q))

    {

        for(int i=0;i<n;i++)

            for(int j=0;j<m;j++)

                scanf("%d",&f[i*m+j]);

        ini(1,0,n-1);

        for(int i=0;i<q;i++)

        {

            scanf("%d%d%d%d",&r1,&c1,&r2,&c2);

            printf("%d\n",find(1,0,n-1));

        }

    }

    return 0;

}

// Fastest known solution for this problem: