// Original C++ solution (slower):
#include<cstdio>

#include<vector>

#include<cstdlib>



#define rep(i,n) for(int i=0;i<(n);i++)



using namespace std;



typedef vector<int> vi;

typedef vector<vi>  vvi;



const int INF=(1<<31)-1;



template<class T> struct Interval{

	T a,b;

	Interval(){}

	Interval(T A,T B):a(A),b(B){}

};



template<class T>

class RMQ{

	int n;

	// vector<T> a;

	T *a;



	T query(const Interval<int> &I,const Interval<int> &J,int u){

		if(J.b<=I.a || I.b<=J.a) return INF;

		if(I.a<=J.a && J.b<=I.b) return a[u];



		int m=(J.a+J.b)/2;

		T tl=query(I,Interval<int>(J.a,m),2*u+1);

		T tr=query(I,Interval<int>(m,J.b),2*u+2);

		return tl<tr?tl:tr;

	}



public:

	RMQ():a(NULL){}



	RMQ(const vector< vector<T> > &v,int k,int b):n(1){

		int N;

		if(!b) N=v[0].size();

		else   N=v.size();



		while(n<N) n<<=1;

		// a=vector<T>(2*n-1);

		a=(T *)malloc((2*n-1)*sizeof(T));

		rep(i,2*n-1) a[i]=0;



		if(!b) rep(i,N) a[n+i-1]=v[k][i];

		else   rep(i,N) a[n+i-1]=v[i][k];



		for(int i=n-2;i>=0;i--) a[i]=min(a[2*i+1],a[2*i+2]);

	}



	// ~RMQ(){ if(a){ free(a); printf("> hoge\n");} else puts("hogehoge"); }



	T query(int a,int b){

		return query(Interval<int>(a,b),Interval<int>(0,n),0);

	}

};



int main(){

	for(int h,w,q;scanf("%d%d%d",&h,&w,&q),h||w||q;){

		vvi a(h,vi(w));

		rep(i,h) rep(j,w) scanf("%d",&a[i][j]);



		vector< RMQ<int> > rmq1(h);

		vector< RMQ<int> > rmq2(w);

		rep(i,h) rmq1[i]=RMQ<int>(a,i,0);

		rep(j,w) rmq2[j]=RMQ<int>(a,j,1);



		rep(_,q){

			int t,l,b,r; scanf("%d%d%d%d",&t,&l,&b,&r); b++; r++;



			int ans=INF;

			if(b-t<r-l) for(int i=t;i<b;i++) ans=min(ans,rmq1[i].query(l,r));

			else        for(int j=l;j<r;j++) ans=min(ans,rmq2[j].query(t,b));

			printf("%d\n",ans);

		}

	}



	return 0;

}

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

#include<vector>

#include<cstdlib>



#define rep(i,n) for(int i=0;i<(n);i++)



using namespace std;



typedef vector<int> vi;

typedef vector<vi>  vvi;



const int INF=(1<<31)-1;



template<class T> struct Interval{

	T a,b;

	Interval(){}

	Interval(T A,T B):a(A),b(B){}

};



int h,w,a[1000000];



template<class T>

class RMQ{

	int n;

	T *a;



	T query(const Interval<int> &I,const Interval<int> &J,int u){

		if(J.b<=I.a || I.b<=J.a) return INF;

		if(I.a<=J.a && J.b<=I.b) return a[u];



		int m=(J.a+J.b)/2;

		T tl=query(I,Interval<int>(J.a,m),2*u+1);

		T tr=query(I,Interval<int>(m,J.b),2*u+2);

		return tl<tr?tl:tr;

	}



public:

	RMQ(){}



	RMQ(int k,int b):n(1){

		int N;

		if(!b) N=w;

		else   N=h;



		while(n<N) n<<=1;

		a=(T *)malloc((2*n-1)*sizeof(T));

		rep(i,2*n-1) a[i]=0;



		if(!b) rep(i,N) a[n+i-1]=::a[k*w+i];

		else   rep(i,N) a[n+i-1]=::a[i*w+k];



		for(int i=n-2;i>=0;i--) a[i]=min(a[2*i+1],a[2*i+2]);

	}



	T query(int a,int b){

		return query(Interval<int>(a,b),Interval<int>(0,n),0);

	}

};



int main(){

	for(int q;scanf("%d%d%d",&h,&w,&q),h||w||q;){

		rep(i,h) rep(j,w) scanf("%d",a+(i*w+j));



		RMQ<int> *rmq1=(RMQ<int> *)malloc(h*sizeof(RMQ<int>));

		RMQ<int> *rmq2=(RMQ<int> *)malloc(w*sizeof(RMQ<int>));

		rep(i,h) rmq1[i]=RMQ<int>(i,0);

		rep(j,w) rmq2[j]=RMQ<int>(j,1);



		rep(_,q){

			int t,l,b,r; scanf("%d%d%d%d",&t,&l,&b,&r); b++; r++;



			int ans=INF;

			if(b-t<r-l) for(int i=t;i<b;i++) ans=min(ans,rmq1[i].query(l,r));

			else        for(int j=l;j<r;j++) ans=min(ans,rmq2[j].query(t,b));

			printf("%d\n",ans);

		}



		free(rmq1);

		free(rmq2);

	}



	return 0;

}

// Fastest known solution for this problem: