Problem:
Problem G: School of Killifish
Jon is the leader of killifish.
Jon have a problem in these days.
Jon has a plan to built new town in a pond.
Of course new towns should have a school for children. But there are some natural enemies in a pond.
Jon thinks that the place of a school should be the safest place in a pond for children.
Jon has asked by some construction companies to make construction plans and Jon has
q
construction plans now.
The plan is selected by voting. But for each plan, the safest place for the school should be decided before voting.
A pond is expressed by a 2D grid whose size is
r*c
.
The grid has
r
rows and
c
columns. The coordinate of the top-left cell is (0,0). The coordinate of the bottom-right cell is expressed as (
r
-1,
c
-1).
Each cell has an integer which implies a dangerousness.
The lower value implies safer than the higher value.
q
plans are given by four integer
r1
,
c1
,
r2
and
c2
which represent the subgrid. 
The top-left corner is (
r1
,
c1
) and the bottom-right corner is (
r2
,
c2
).
You have the
r*c
grid and
q
plans. Your task is to find the safest point for each plan.
You should find the lowest value in the subgrid.
Input
Input consists of multiple datasets.
Each dataset is given in the following format.
r
c
q
grid
0,0
grid
0,1
...
grid
0,c-1
...
grid
r-1,0
...
grid
r-1,c-1
r1
c1
r2
c2
...
r1
c1
r2
c2
The first line consists of 3 integers,
r
,
c
, and
q
.
Next
r
lines have
c
integers.
grid
i,j
means a dangerousness of the grid.
And you can assume 0 ≤
grid
i,j
≤ 2
31
-1.
After that,
q
queries,
r1
,
c1
,
r2
and
c2
,  are given.
The dataset satisfies following constraints.
r*c
≤ 10
6
q
≤ 10
4
For each query, you can assume that
r1
≤
r2
and
c1
≤
c2
.

If
r * c
≤ 250000,
q
≤ 100 is assured.
If
r * c
> 250000, Input consists of only that case.
Output
For each query you should print the lowest value in the subgrid in a line.
Sample input
3 3 4
1 2 3
4 2 2
2 1 1
0 0 2 2
0 0 1 1
1 0 1 0
0 1 1 2
1 10 4
1 2 3 4 5 6 7 8 9 10
0 0 0 9
0 0 0 4
0 5 0 9
0 4 0 5
0 0 0
Sample output
1
1
4
2
1
1
6
5

Submitted solutions:

code_snippet: /*
 *       Author:  8mao
 * Created Time:  2014/3/16 20:09:19
 *    File Name:  2009.cpp
 */
# include<map>
# include<set>
# include<cmath>
# include<queue>
# include<stack>
# include<vector>
# include<string>
# include<cstdio>
# include<climits>
# include<cstring>
# include<iostream>
# include<algorithm>
# include<functional>
using namespace std;

typedef pair<int,int> PII;
# define INF 1<<30
# define LL long long
# define MOD 1000000007
# define VI vector<int>
# define VLL vector<LL>
# define VS vector<string>
# define PII pair<int,int>

# define F first
# define S second
# define mp make_pair
# define pb push_back
# define lb lower_bound
# define up upper_bound
# define lowbit(x)(x&-x)
# define lson l,m,rt<<1
# define rson m+1,r,rt<<1|1
# define clr(x) (x).clear()
# define sz(x) ((int)(x).size())
# define all(x) (x).begin(),(x).end()
# define mem(x,y) memset(x,y,sizeof(x))
# define forall(it,c) for(typeof((c).begin())it=(c).begin();it!=(c).end();it++)


struct SegTree
{
    VI Min, a;
    int n;
    
    
    void init(vector<int> v)
    {
        n = sz(v);
        a = v;
        Min.resize(n << 2);
        Build(0, n - 1, 1);
    }
    
    void PushUp(int rt)
    {
        Min[rt] = min (Min[rt << 1], Min[rt << 1 | 1]);
    }

    void Build(int l, int r, int rt)
    {
        int m;
        if (l == r)
        {
            Min[rt] = a[l];
            return ; 
        }
        m = (l + r) >> 1;
        Build(lson);
        Build(rson);
        PushUp(rt);
    }

    int Query(int L, int R, int l, int r, int rt)
    {
        int m, ans = INT_MAX;
        if (L <= l && R >= r)
            return Min[rt];
        m = (l + r) >> 1;
        if (L <= m) ans = min (ans, Query(L, R, lson));
        if (R > m) ans = min (ans, Query(L, R, rson));
        return ans; 
    }    
    
    int getMin(int l, int r)
    {
        return Query(l, r, 0, n - 1, 1); 
    }
};


int main()
{
    //freopen("in.txt","r",stdin);
    int i, j, n, m, q, l, r, ans, x1, y1, x2, y2, limit;
    vector<SegTree> seg;
    while (scanf ("%d %d %d", &n, &m, &q) != EOF && (n + m + q))
    {
        vector<VI> v(min (n, m), VI (max (n, m)));
        seg.resize(min (n, m));
        for (i = 0; i < n; i++)
            for (j = 0; j < m; j++)
            {
                if (n <= m) scanf ("%d", &v[i][j]);
                else scanf ("%d", &v[j][i]);
            }
        limit = min (n, m);
        for (i = 0; i < limit; i++)
            seg[i].init(v[i]);
        while (q--)
        {
            ans = INT_MAX;
            scanf ("%d %d %d %d", &x1, &y1, &x2, &y2);
            if (n <= m)
            {
                for (i = x1; i <= x2; i++)
                    ans = min (ans, seg[i].getMin(y1, y2));
            }
            else
            {
                for (i = y1; i <= y2; i++)
                    ans = min (ans, seg[i].getMin(x1, x2));
            }
            printf ("%d\n", ans);
        }
    }
    return 0;
}
accuracy: 1
time_ms: 610
memory_kb: 30536
final_rank: 2

code_snippet: #include <iostream>
#include <iomanip>//小数点出力用
//cout << fixed << setprecision(10) << ans;
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <unordered_map>
using ll = long long;
using namespace std;
#define modPHash (ll)((1LL<<61)-1)
#define modP (ll)998244353
bool chkrng0idx(int pos, int sup) { return (0 <= pos && pos < sup); }
int clk4(int num) { return (num - 2) * (num % 2); }
void yn(bool tf) { cout << (tf ? "Yes\n" : "No\n"); }
#include <iostream>
#include <iomanip>//小数点出力用
//cout << fixed << setprecision(10) << ans;
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
using ll = long long;
using namespace std;
#define modP 998244353
int segLenH, segLenW;
vector<vector<ll>>segT;

void init(int hei, int wei) {
    segLenH = 1;
    hei--;
    while (hei >= 1) {
        segLenH <<= 1;
        hei >>= 1;
    }
    segLenW = 1;
    wei--;
    while (wei >= 1) {
        segLenW <<= 1;
        wei >>= 1;
    }
    vector<ll>initW(segLenW * 2, (ll)1e15);
    segT = vector<vector<ll>>(segLenH * 2, initW);
}

int c2(int X) {
    int res = 0;
    int t = X;
    if (t == 0)t = max(segLenH, segLenW);
    while (1) {
        if (t % 2 == 0) {
            t /= 2;
            res++;
        }
        else {
            break;
        }
    }
    return res;
}

void update(int X, int Y, ll obj) {
    segT[X + segLenH][Y + segLenW] = obj;
    int i = X + segLenH;
    while (i >= 1) {
        if (i != X + segLenH) {
            segT[i][Y + segLenW] = min(segT[i << 1][Y + segLenW], segT[(i << 1) + 1][Y + segLenW]);
        }
        int j = ((Y + segLenW) >> 1);
        while (j >= 1) {
            segT[i][j] = min(segT[i][j << 1], segT[i][(j << 1) + 1]);
            j >>= 1;
        }
        i >>= 1;
    }
}

ll getM(int XL, int XR, int YL, int YR) {
    int tL = XL;
    vector<int>interX;
    while (tL != XR) {
        int b = c2(tL);
        for (;b >= 0;b--) {
            if (tL + (1 << b) <= XR) {
                int segIdx = (tL + segLenH) >> b;
                interX.push_back(segIdx);
                //res = max(res, segT[segIdx]);
                tL += (1 << b);
                break;
            }
        }
    }
    tL = YL;
    vector<int>interY;
    while (tL != YR) {
        int b = c2(tL);
        for (;b >= 0;b--) {
            if (tL + (1 << b) <= YR) {
                int segIdx = (tL + segLenW) >> b;
                interY.push_back(segIdx);
                //res = max(res, segT[segIdx]);
                tL += (1 << b);
                break;
            }
        }
    }
    ll res = 1e15;
    for (int i = 0;i < interX.size();i++) {
        for (int j = 0;j < interY.size();j++) {
            res = min(res, segT[interX[i]][interY[j]]);
        }
    }
    return res;
}


int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    while (1) {
        int H, W, Q;
        cin >> H >> W >> Q;
        if (!H)break;
        init(H, W);
        for (int i = 0; i < H; i++) {
            for (int j = 0; j < W; j++) {
                int a;
                cin >> a;
                update(i, j, a);
            }
        }
        while (Q--) {
            int xm, ym, XM, YM;
            cin >> xm >> ym >> XM >> YM;
            cout << getM(xm, XM + 1, ym, YM + 1) << "\n";
        }
    }
    return 0;
}
accuracy: 1
time_ms: 230
memory_kb: 117564
final_rank: 14

code_snippet: #include<stdio.h>
#define la (tr[rt].a)
#define lb (tr[rt].b)
#define lc (tr[rt].c)
#define ld (tr[rt].d)
#define MIN(A,B) ((A)>(B)?(B):(A))
using namespace std;
struct seg{
    int x1,y1,x2,y2;
    int v;
    int a,b,c,d;
    int midx(){
        return (x1+x2)>>1;
    }
    int midy(){
        return (y1+y2)>>1;
    }
}tr[20000010];
int matrix[10000010];
int tot;
int r,c,q;
void build(int rt,int x1,int y1,int x2,int y2)
{
    //printf("%d %d %d %d %d\n",rt,x1,y1,x2,y2);
    tr[rt].x1 = x1;
    tr[rt].y1 = y1;
    tr[rt].x2 = x2;
    tr[rt].y2 = y2;
    if(x1>=x2&&y1>=y2){
        tr[rt].v = matrix[x1*c+y1];
        return;
    }
    int mx = tr[rt].midx();
    int my = tr[rt].midy();
    if(x1 == x2){
        tr[rt].a = ++tot;
        tr[rt].b = ++tot;
        build(la,x1,y1,mx,my);
        build(lb,x1,my+1,mx,y2);
        tr[rt].v = MIN(tr[la].v,tr[lb].v);
        return;
    }
    else if(y1 == y2){
        tr[rt].a = ++tot;
        tr[rt].c = ++tot;
        build(la,x1,y1,mx,my);
        build(lc,mx+1,y1,x2,my);
        tr[rt].v = MIN(tr[la].v,tr[lc].v);
        return;
    }
    else{
        tr[rt].a = ++tot;
        tr[rt].b = ++tot;
        tr[rt].c = ++tot;
        tr[rt].d = ++tot;
        build(la,x1,y1,mx,my);
        build(lb,x1,my+1,mx,y2);
        build(lc,mx+1,y1,x2,my);
        build(ld,mx+1,my+1,x2,y2);
        tr[rt].v = MIN(tr[la].v,tr[lb].v);
        tr[rt].v = MIN(tr[rt].v,tr[lc].v);
        tr[rt].v = MIN(tr[rt].v,tr[ld].v);
        return;
    }
}
int query(int rt,int x1,int y1,int x2,int y2)
{
    if(x1==tr[rt].x1&&x2==tr[rt].x2&&y2==tr[rt].y2&&y1==tr[rt].y1){
        return tr[rt].v;
    }
    int mx = tr[rt].midx();
    int my = tr[rt].midy();
    //1
    if(x2<=mx&&y2<=my)
        return query(la,x1,y1,x2,y2);
    if(y1>my&&x2<=mx)
        return query(lb,x1,y1,x2,y2);
    if(x1>mx&&y2<=my)
        return query(lc,x1,y1,x2,y2);
    if(mx<x1&&my<y1)
        return query(ld,x1,y1,x2,y2);
    //2
    if(x2<=mx){
        int a = query(la,x1,y1,x2,my);
        int b = query(lb,x1,my+1,x2,y2);
        return MIN(a,b);
    }
    if(y2<=my){
        int a = query(la,x1,y1,mx,y2);
        int b = query(lc,mx+1,y1,x2,y2);
        return MIN(a,b);
    }
    if(x1>mx){
        int a = query(lc,x1,y1,x2,my);
        int b = query(ld,x1,my+1,x2,y2);
        return MIN(a,b);
    }
    if(y1>my){
        int a = query(lb,x1,y1,mx,y2);
        int b = query(ld,mx+1,y1,x2,y2);
        return MIN(a,b);
    }
    //3
    int a = query(la,x1,y1,mx,my);
    int b = query(lb,x1,my+1,mx,y2);
    int c = query(lc,mx+1,y1,x2,my);
    int d = query(ld,mx+1,my+1,x2,y2);
    int e = MIN(a,b);
    e = MIN(e,c);
    e = MIN(e,d);
    return e;
}
int main()
{
    //freopen("d:\\in.txt","r",stdin);
    while(scanf("%d%d%d",&r,&c,&q),r||c||q){
        tot = 0;
        for(int i = 0; i < r; ++i){
            for(int j = 0; j < c; ++j){
                scanf("%d",matrix+i*c+j);
            }
        }
        build(0,0,0,r-1,c-1);
        for(int i = 0; i < q; ++i){
            int a,b,c,d;
            scanf("%d%d%d%d",&a,&b,&c,&d);
            printf("%d\n",query(0,a,b,c,d));
        }
    }
    return 0;
}
accuracy: 1
time_ms: 340
memory_kb: 78720
final_rank: 8

code_snippet: #include<stdio.h>
#include<string.h>
#include<limits.h>
#include<vector>
using namespace std;


const int maxn = 1000000*3;

vector<int> A[ 1000009 ];
int n;
struct node
{
    int x1,x2,y1,y2;
    int min;
    int ch[4];
};
node tree[maxn];
 
int tol;
 
void maketree(int x1,int x2,int y1,int y2)
{
    int k = ++tol;
    tree[k].x1 = x1;
    tree[k].x2 = x2;
    tree[k].y1 = y1;
    tree[k].y2 = y2;
    tree[k].min = 0;
    if(x1 == x2 && y1==y2)
    {
        tree[k].min = A[x1][y1];
        memset(tree[k].ch,0,sizeof(tree[k].ch));
        return ;
    }
    
    int midx = (x1+x2)>>1;
    int midy = (y1+y2)>>1;
    
    tree[k].ch[0] = tol+1;
    maketree(x1,midx,y1,midy); 
    
    if(midx+1 <= x2 && midy+1 <= y2) 
    {
        tree[k].ch[1] = tol+1;
        maketree(midx+1,x2,midy+1,y2);
    }
    else
        tree[k].ch[1] = 0;
    
    if(midy+1 <= y2)    
    {
        tree[k].ch[2] = tol+1;
        maketree(x1,midx,midy+1,y2);
    }
    else
        tree[k].ch[2] = 0;
    
 
    if(midx+1 <= x2)
    {
        tree[k].ch[3] = tol+1;
        maketree(midx+1,x2,y1,midy);
    }
    else
        tree[k].ch[3] = 0;
        
    tree[k].min =  tree[tree[k].ch[0]].min;
    for(int i=1; i<4; i++)            
        if(tree[k].ch[i])
            tree[k].min = min(tree[k].min,tree[tree[k].ch[i]].min);
}
 
inline bool cross(int x1,int x2,int y1,int y2,int k)
{
    if(x2 < tree[k].x1 || tree[k].x2 < x1   ||  y2 < tree[k].y1 || tree[k].y2 < y1)
        return false;
    return true;
}
 
int Query(int x1,int x2,int y1,int y2,int k) 
{
    if(cross(x1,x2,y1,y2,k) == 0)  
        return INT_MAX;
 
    if(x1 <= tree[k].x1 && tree[k].x2 <= x2 && y1<= tree[k].y1 && tree[k].y2 <= y2) 
        return tree[k].min;
    int minx = Query(x1,x2,y1,y2,tree[k].ch[0]);
 
    for(int i=1; i<4; i++)
        minx = min(minx,Query(x1,x2,y1,y2,tree[k].ch[i]));
    return minx;
}

int main()
{
    int r,c,q,temp;
    int x1,y1,x2,y2;
    while(( scanf( "%d%d%d",&r,&c,&q ),r ))
    {
        for( int i=1;i<=r;i++ ){
            if( A[ i ].size(  )<=1 )
                A[ i ].push_back( 0 );
            for( int j=1;j<=c;j++ ){
                scanf( "%d",&temp );
                if( j>=A[ i ].size(  ) ){
                    A[ i ].push_back( temp );
                }
                else{
                    A[ i ][ j ]=temp;
                }
            }
        }
        tol=0;
        maketree(1,r,1,c);        
        while(q--)
        {
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            x1++,y1++,x2++,y2++;
            printf("%d\n",Query(x1,x2,y1,y2,1));
        }
    }
}
accuracy: 1
time_ms: 460
memory_kb: 130312
final_rank: 17

code_snippet: #include <iostream>
#include <map>
#include <algorithm>
#include <stdio.h>


using namespace std;

const int maxn = 5000700;

struct Node
{
    //int lx,ly,rx,ry;
    int lc,rc;
    int mini;
} tree[maxn];

int last,R,C,Q;
int a[1000007];

void build(int lx,int ly,int rx,int ry,int &now)
{
    now = last++;
    if (ry-ly > rx-lx)
    {
        int mid = (ry+ly) >> 1;
        build(lx,ly,rx,mid,tree[now].lc);
        build(lx,mid+1,rx,ry,tree[now].rc);
        tree[now].mini = min(tree[tree[now].lc].mini,tree[tree[now].rc].mini);
    }
    else
    {
        if (rx > lx)
        {
            int mid = (rx+lx) >> 1;
            build(lx,ly,mid,ry,tree[now].lc);
            build(mid+1,ly,rx,ry,tree[now].rc);
            tree[now].mini = min(tree[tree[now].lc].mini,tree[tree[now].rc].mini);
        }
        else
        {
            tree[now].mini = a[lx*C+ly];
        }
    }
}

void quary(int Lx,int Ly,int Rx,int Ry,int lx,int ly,int rx,int ry,int now,int &mini)
{
    if (Lx <= lx && Ly <= ly && Rx >= rx && Ry >= ry)
    {
        mini = min(mini,tree[now].mini);
        return;
    }
    if (ry-ly > rx-lx)
    {
        int mid = (ry+ly) >> 1;
        if (Ly <= mid) quary(Lx,Ly,Rx,Ry,lx,ly,rx,mid,tree[now].lc,mini);
        if (Ry > mid) quary(Lx,Ly,Rx,Ry,lx,mid+1,rx,ry,tree[now].rc,mini);
    }
    else
    {
        if (rx > lx)
        {
            int mid = (rx+lx) >> 1;
            if (Lx <= mid) quary(Lx,Ly,Rx,Ry,lx,ly,mid,ry,tree[now].lc,mini);
            if (Rx > mid) quary(Lx,Ly,Rx,Ry,mid+1,ly,rx,ry,tree[now].rc,mini);
        }
    }

}

int main()
{
    while (1)
    {
        cin >> R;
        if (0 == R) break;
        cin >>  C >> Q;
        for (int i = 0;i < R*C;++i) scanf("%d",&a[i]);
        int root;
        last = 0;
        build(0,0,R-1,C-1,root);
        while (Q--)
        {
            int r1,c1,r2,c2;
            scanf("%d%d%d%d",&r1,&c1,&r2,&c2);
            int mini = 0x7fffffff;
            quary(r1,c1,r2,c2,0,0,R-1,C-1,root,mini);
            printf("%d\n",mini);
        }
    }
    return 0;
}
accuracy: 1
time_ms: 2690
memory_kb: 32196
final_rank: 19

code_snippet: #include <iostream>
#include <map>
#include <algorithm>
#include <stdio.h>


using namespace std;

const int maxn = 4000700;

struct Node
{
    //int lx,ly,rx,ry;
    int lc,rc;
    int mini;
} tree[maxn];

int last,R,C,Q;
int a[1000007];

void build(int lx,int ly,int rx,int ry,int &now)
{
    now = last++;
    if (ry-ly > rx-lx)
    {
        int mid = (ry+ly) >> 1;
        build(lx,ly,rx,mid,tree[now].lc);
        build(lx,mid+1,rx,ry,tree[now].rc);
        tree[now].mini = min(tree[tree[now].lc].mini,tree[tree[now].rc].mini);
    }
    else
    {
        if (rx > lx)
        {
            int mid = (rx+lx) >> 1;
            build(lx,ly,mid,ry,tree[now].lc);
            build(mid+1,ly,rx,ry,tree[now].rc);
            tree[now].mini = min(tree[tree[now].lc].mini,tree[tree[now].rc].mini);
        }
        else
        {
            tree[now].mini = a[lx*C+ly];
        }
    }
}

void quary(int Lx,int Ly,int Rx,int Ry,int lx,int ly,int rx,int ry,int now,int &mini)
{
    if (Lx <= lx && Ly <= ly && Rx >= rx && Ry >= ry)
    {
        mini = min(mini,tree[now].mini);
        return;
    }
    if (ry-ly > rx-lx)
    {
        int mid = (ry+ly) >> 1;
        if (Ly <= mid) quary(Lx,Ly,Rx,Ry,lx,ly,rx,mid,tree[now].lc,mini);
        if (Ry > mid) quary(Lx,Ly,Rx,Ry,lx,mid+1,rx,ry,tree[now].rc,mini);
    }
    else
    {
        if (rx > lx)
        {
            int mid = (rx+lx) >> 1;
            if (Lx <= mid) quary(Lx,Ly,Rx,Ry,lx,ly,mid,ry,tree[now].lc,mini);
            if (Rx > mid) quary(Lx,Ly,Rx,Ry,mid+1,ly,rx,ry,tree[now].rc,mini);
        }
    }

}

int main()
{
    while (cin >> R >> C >> Q)
    {
        if (!R && !C && !Q) break;
        for (int i = 0;i < R*C;++i) scanf("%d",&a[i]);
        int root;
        last = 0;
        build(0,0,R-1,C-1,root);
        while (Q--)
        {
            int r1,c1,r2,c2;
            scanf("%d%d%d%d",&r1,&c1,&r2,&c2);
            int mini = 0x7fffffff;
            quary(r1,c1,r2,c2,0,0,R-1,C-1,root,mini);
            printf("%d\n",mini);
        }
    }
    return 0;
}
accuracy: 1
time_ms: 2640
memory_kb: 32188
final_rank: 18

code_snippet: #include <bits/stdc++.h>
using namespace std;

// 二次元セグメント木
template <class S, auto op, auto e>
struct segtree2d
{
    static_assert(std::is_convertible_v<decltype(op), std::function<S(S, S)>>,
                  "op must work as S(S, S)");
    static_assert(std::is_convertible_v<decltype(e), std::function<S()>>,
                  "e must work as S()");

public:
    segtree2d() : segtree2d(0) {}
    explicit segtree2d(int h, int w)
    {
        init(h, w);
    }

    explicit segtree2d(const std::vector<std::vector<S>> &v)
    {
        init(v.size(), v[0].size());

        for (int i = 0; i < _h; i++)
        {
            for (int j = 0; j < _w; j++)
            {
                values[id(size_h + i, size_w + j)] = v[id(i, j)];
            }
        }

        for (int w = size_w; w < size_w * 2; w++)
        {
            for (int h = size_h - 1; h >= 1; h--)
            {
                update_h(h, w);
            }
        }

        for (int h = 0; h < size_h * 2; h++)
        {
            for (int w = size_w - 1; w >= 1; w--)
            {
                update_w(h, w);
            }
        }
    }

    void set(int p_h, int p_w, S x)
    {
        assert(0 <= p_h && p_h < _h);
        assert(0 <= p_w && p_w < _w);

        p_h += size_h;
        p_w += size_w;

        values[id(p_h, p_w)] = x;

        for (int i = p_h >> 1; i; i >>= 1)
        {
            update_h(i, p_w);
        }

        for (; p_h; p_h >>= 1)
        {
            for (int j = p_w >> 1; j; j >>= 1)
            {
                update_w(p_h, j);
            }
        }
    }

    S get(int p_h, int p_w) const
    {
        assert(0 <= p_h && p_h < _h);
        assert(0 <= p_w && p_w < _w);

        return values[id(p_h + size_h, p_w + size_w)];
    }

    S prod(int t, int l, int d, int r) const
    {
        assert(0 <= t && t <= d && t <= _h);
        assert(0 <= l && l <= r && r <= _w);

        S smt = e(), smd = e();
        t += size_h;
        d += size_h;
        l += size_w;
        r += size_w;

        for (; t < d; t >>= 1, d >>= 1)
        {
            if (t & 1)
                smt = op(smt, inner_prod(t++, l, r));
            if (d & 1)
                smd = op(inner_prod(--d, l, r), smd);
        }

        return op(smt, smd);
    }

private:
    int _n, size_h, size_w;
    int _h, _w;
    std::vector<S> values;

    void init(int h, int w)
    {
        _h = h;
        _w = w;
        size_h = (int)std::bit_ceil((unsigned int)(_h));
        size_w = (int)std::bit_ceil((unsigned int)(_w));

        values = std::vector<S>(size_h * size_w * 4, e());
    }

    int id(int h, int w) const
    {
        return h * 2 * size_w + w;
    }

    void update_h(int h, int w)
    {
        values[id(h, w)] = op(values[id(2 * h, w)], values[id(2 * h + 1, w)]);
    }

    void update_w(int h, int w)
    {
        values[id(h, w)] = op(values[id(h, 2 * w)], values[id(h, 2 * w + 1)]);
    }

    S inner_prod(int h, int l, int r) const
    {
        S sml = e(), smr = e();

        for (; l < r; l >>= 1, r >>= 1)
        {
            if (l & 1)
                sml = op(sml, values[id(h, l++)]);
            if (r & 1)
                smr = op(values[id(h, --r)], smr);
        }

        return op(sml, smr);
    }
};

#include <bits/stdc++.h>

using namespace std;

long long op(long long a, long long b)
{
    return min(a, b);
}

long long e()
{
    return INT32_MAX;
}

void solve(int r, int c, int q)
{
    segtree2d<long long, op, e> seg(r, c);
    for (int h = 0; h < r; h++)
    {
        for (int w = 0; w < c; w++)
        {
            long long grid;
            cin >> grid;
            seg.set(h, w, grid);
        }
    }

    for (int Q = 0; Q < q; Q++)
    {
        int r1, c1, r2, c2;
        cin >> r1 >> c1 >> r2 >> c2;

        int ans = seg.prod(r1, c1, r2 + 1, c2 + 1);
        cout << ans << endl;
    }
}

int main()
{

    while (true)
    {
        int r, c, q;
        cin >> r >> c >> q;
        if (r == 0 && c == 0 && q == 0)
        {
            break;
        }

        solve(r, c, q);
    }

    return 0;
}
accuracy: 1
time_ms: 330
memory_kb: 68944
final_rank: 7

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll INF = 2e+18;

template <typename T> struct SegmentTree2D {
    int H, W;
    vector<T> data;
    T identity = INF;  // TODO: Set identity value.
    T op(T l, T r) {return min(l, r);}  // TODO: Set op function.

    SegmentTree2D(int h, int w) {
        H = 1; W = 1;
        while (H < h) H *= 2;
        while (W < w) W *= 2;
        data.assign(4*H*W, identity);
    }

    int id(int h, int w) {return h*2*W + w;}

    void initialize(int h, int w, T x) {
        data[id(h+H, w+W)] = x;
    }

    void build() {
        for (int w = W; w < 2*W; w++) {
            for (int h = H-1; h > 0; h--) {
                data[id(h, w)] = op(data[id(2*h, w)], data[id(2*h+1, w)]);
            }
        }
        for (int h = 0; h < 2*H; h++) {
            for (int w = W-1; w > 0; w--) {
                data[id(h, w)] = op(data[id(h, 2*w)], data[id(h, 2*w+1)]);
            }
        }
    }

    void update(int h, int w, T x) {
        h += H; w += W;
        data[id(h, w)] = x;
        for (int i = (h >> 1); i > 0; i >>= 1) {
            data[id(i,w)] = op(data[id(2*i, w)], data[id(2*i+1, w)]);
        }
        for (; h > 0; h >>= 1) {
            for (int j = (w >> 1); j > 0; j >>= 1) {
                data[id(h,j)] = op(data[id(h, 2*j)], data[id(h, 2*j+1)]);
            }
        }
    }

    T _sub_query(int h, int w1, int w2) {
        T res = identity;
        for (; w1 < w2; w1 >>= 1, w2 >>= 1) {
            if (w1 & 1) {
                res = op(res, data[id(h, w1)]);
                w1++;
            }
            if (w2 & 1) {
                w2--;
                res = op(res, data[id(h, w2)]);
            }
        }
        return res;
    }

    T query(int h1, int w1, int h2, int w2) {
        // Return the answer to the query of [h1, h2) * [w1, w2)
        if (h1 >= h2 || w1 >= w2) return identity;
        T res = identity;
        h1 += H; h2 += H; w1 += W; w2 += W;
        for (; h1 < h2; h1 >>= 1, h2 >>= 1) {
            if (h1 & 1) {
                res = op(res, _sub_query(h1, w1, w2));
                h1++;
            }
            if (h2 & 1) {
                h2--;
                res = op(res, _sub_query(h2, w1, w2));
            }
        }
        return res;
    }
};

bool solve() {
    ll R, C, Q;
    cin >> R >> C >> Q;
    if (R == 0 && C == 0 && Q == 0) return true;

    SegmentTree2D<ll> st(R, C);
    for (int r = 0; r < R; r++) {
        for (int c = 0; c < C; c++) {
            ll x;
            cin >> x;
            st.update(r, c, x);
        }
    }

    while (Q--) {
        ll r1, c1, r2, c2;
        cin >> r1 >> c1 >> r2 >> c2;
        r2++; c2++;
        cout << st.query(r1, c1, r2, c2) << "\n";
    }

    return false;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout << fixed << setprecision(15);
    bool done = false;
    while (!done) done = solve();
}
accuracy: 1
time_ms: 270
memory_kb: 68448
final_rank: 6

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll INF = 2e+18;

template <typename T> struct SegmentTree2D {
    int H, W;
    vector<T> data;
    T identity = INF;  // TODO: Set identity value.
    T op(T l, T r) {return min(l, r);}  // TODO: Set op function.

    SegmentTree2D(int h, int w) {
        H = 1; W = 1;
        while (H < h) H *= 2;
        while (W < w) W *= 2;
        data.assign(4*H*W, identity);
    }

    int id(int h, int w) {return h*2*W + w;}

    void initialize(int h, int w, T x) {
        data[id(h+H, w+W)] = x;
    }

    void build() {
        for (int w = W; w < 2*W; w++) {
            for (int h = H-1; h > 0; h--) {
                data[id(h, w)] = op(data[id(2*h, w)], data[id(2*h+1, w)]);
            }
        }
        for (int h = 0; h < 2*H; h++) {
            for (int w = W-1; w > 0; w--) {
                data[id(h, w)] = op(data[id(h, 2*w)], data[id(h, 2*w+1)]);
            }
        }
    }

    void update(int h, int w, T x) {
        h += H; w += W;
        data[id(h, w)] = x;
        for (int i = (h >> 1); i > 0; i >>= 1) {
            data[id(i,w)] = op(data[id(2*i, w)], data[id(2*i+1, w)]);
        }
        for (; h > 0; h >>= 1) {
            for (int j = (w >> 1); j > 0; j >>= 1) {
                data[id(h,j)] = op(data[id(h, 2*j)], data[id(h, 2*j+1)]);
            }
        }
    }

    T _sub_query(int h, int w1, int w2) {
        T res = identity;
        for (; w1 < w2; w1 >>= 1, w2 >>= 1) {
            if (w1 & 1) {
                res = op(res, data[id(h, w1)]);
                w1++;
            }
            if (w2 & 1) {
                w2--;
                res = op(res, data[id(h, w2)]);
            }
        }
        return res;
    }

    T query(int h1, int w1, int h2, int w2) {
        // Return the answer to the query of [h1, h2) * [w1, w2)
        if (h1 >= h2 || w1 >= w2) return identity;
        T res = identity;
        h1 += H; h2 += H; w1 += W; w2 += W;
        for (; h1 < h2; h1 >>= 1, h2 >>= 1) {
            if (h1 & 1) {
                res = op(res, _sub_query(h1, w1, w2));
                h1++;
            }
            if (h2 & 1) {
                h2--;
                res = op(res, _sub_query(h2, w1, w2));
            }
        }
        return res;
    }
};

bool solve() {
    ll R, C, Q;
    cin >> R >> C >> Q;
    if (R == 0 && C == 0 && Q == 0) return true;

    SegmentTree2D<ll> st(R, C);
    for (int r = 0; r < R; r++) {
        for (int c = 0; c < C; c++) {
            ll x;
            cin >> x;
            st.initialize(r, c, x);
        }
    }
    st.build();

    while (Q--) {
        ll r1, c1, r2, c2;
        cin >> r1 >> c1 >> r2 >> c2;
        r2++; c2++;
        cout << st.query(r1, c1, r2, c2) << "\n";
    }

    return false;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout << fixed << setprecision(15);
    bool done = false;
    while (!done) done = solve();
}
accuracy: 1
time_ms: 120
memory_kb: 68548
final_rank: 3

code_snippet: /*#define PROBLEM "https://onlinejudge.u-aizu.ac.jp/problems/1068"
#include "../Utility/template.hpp"
#include "../Datastructure/2dsegtree.hpp"*/
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i, s, t) for (ll i = s; i < (ll)(t); i++)
#define rrep(i, s, t) for(ll i = (ll)(t) - 1; i >= (ll)(s); i--)
#define all(x) begin(x), end(x)
#define rall(x) rbegin(x), rend(x)

#define TT template<typename T>
TT using vec = vector<T>;
TT bool chmin(T &x, T y) { return x > y ? (x = y, true) : false; }
TT bool chmax(T &x, T y) { return x < y ? (x = y, true) : false; }

struct io_setup {
    io_setup() {
        ios::sync_with_stdio(false);
        std::cin.tie(nullptr);
        cout << fixed << setprecision(15);
    }
} io_setup;

template <class S, S (*op)(S, S), S (*e)()> struct segtree {
    int n;
    int sz;
    vector<S> d;

    segtree(int n) : segtree(vector<S>(n, e())) {}

    segtree(const vector<S> &v) : n((int)v.size()), sz(1) {
        while(sz < n) sz <<= 1;
        d.resize(2*sz, e());
        rep(i, 0, n) {
            d[sz+i] = v[i];
        }
        rrep(i, 1, sz) d[i] = op(d[i<<1], d[i<<1|1]);
    }

    void set(int p, S x) {
        assert(0 <= p && p < n);
        p += sz;
        d[p] = x;
        while(p > 1) {
            p >>= 1;
            d[p] = op(d[p<<1], d[p<<1|1]);
        }
    }

    S get(int p) const {
        assert(0 <= p && p < n);
        return d[p + sz];
    }

    S prod(int l, int r) const {
        assert(0 <= l && l <= r && r <= n);
        S sml = e(), smr = e();
        l += sz;
        r += sz;

        while (l < r) {
            if (l & 1) sml = op(sml, d[l++]);
            if (r & 1) smr = op(d[--r], smr);
            l >>= 1;
            r >>= 1;
        }
        return op(sml, smr);
    }
};

template <class S, S (*op)(S, S), S (*e)()> struct segtree2d {
    int id(int y, int x) {return y * 2 * W + x;} //= y番目のセグ木の、ノードxに対応する添字
    int H, W;
    vec<S> dat;
    bool f;


    segtree2d(int h, int w) {
        f = true;
        H = W = 1;
        while(H < h) H <<= 1;
        while(W < w) W <<= 1;
        dat.resize(4 * H * W, e());
    }


    void preset(int y, int x, S v) {f = false,  dat[id(y + H, x + W)] = v; }

    void build() {
        f = true;
        rep(h, H, 2 * H) {
            rrep(w, 1, W) {
                dat[id(h, w)] = op(dat[id(h, 2 * w)], dat[id(h, 2 * w + 1)]);
            }
        }
        
        rrep(h, 0, H) {
            rrep(w, 1, 2 * W) {
                dat[id(h, w)] = op(dat[id(h * 2, w)], dat[id(h * 2 + 1, w)]);
            } 
        }
    }

    
    void set(int y, int x, S v) {
        assert(f);

        y += H, x += W;
        dat[id(y, x)] = v;
        rrep(w, 1, W) {
            dat[id(y, w)] = op(dat[id(y, 2 * w)], dat[id(y, 2 * w + 1)]);
        }

        while(y > 1) {
            y >>= 1;
            for(int j = x; j >= 1; j >>= 1) {
                dat[id(y, j)] = op(dat[id(y * 2, j)] , dat[id(y * 2 + 1, j)]);
            }
        }
    }

    S inner(int h, int l, int r) {
        S sml = e(), smr = e();
        l += W, r += W;
        while(l < r) {
            if(l & 1) sml = op(sml, dat[id(h, l++)]);
            if(r & 1) smr = op(dat[id(h, --r)], smr);
            l >>= 1, r >>= 1;
        }
        return op(sml, smr);
    }

    S prod(int sy, int ty, int sx, int tx) {
        assert(f);

        S sml = e(), smr = e();
        sy += H, ty += H;
        while(sy < ty) {
            if(sy & 1) sml = op(sml, inner(sy++, sx, tx));
            if(ty & 1) smr = op(inner(--ty, sx, tx), smr);
            sy >>= 1, ty >>= 1;
        }
        return op(sml, smr);
    }

    S get(int y, int x) {
        return dat[id(y + H, x + W)];
    }

    
};

using S = int;
S op(S l, S r) {
    return min(l, r);
}

S e() {
    return INT_MAX;
}

int main() {
    int r, c, q;
    //std::ifstream ifs("in.txt");
    //std::ofstream ofs("test.txt");
    while(cin >> r >> c >> q) {
        if(r==0) break;

        vec<vec<int>> grid(r, vec<int>(c));
        rep(i, 0, r) rep(j, 0, c) cin >> grid[i][j];
    
        segtree2d<S, op, e> seg(r, c);
        rep(i, 0, r) rep(j, 0, c) seg.preset(i, j, grid[i][j]);
        seg.build();
        while(q--) {
            int sy, sx, ty, tx;
            cin >> sy >> sx >> ty >> tx;
            cout << seg.prod(sy, ty+1, sx, tx+1) << '\n';
        }
    }
}
accuracy: 1
time_ms: 90
memory_kb: 74092
final_rank: 5

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
using ull = unsigned long long;
using uint = unsigned int;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using pdd = pair<double, double>;
using tuplis = array<ll, 3>;
template<class T> using vc = vector<T>;
template<class T> using vvc = vc<vc<T>>;
template<class T> using vvvc = vc<vvc<T>>;
template<class T> using vvvvc = vc<vvvc<T>>;
template<class T> using pq = priority_queue<T, vector<T>, greater<T>>;
const int INF = 0x3fffffff;
const ll MINF = 0x7fffffffffff;
const ll LINF = 0x1fffffffffffffff;
const ld DINF = numeric_limits<ld>::infinity();
const int MOD7 = 1000000007;
const int MOD9 = 998244353;
const ld EPS = 1e-9;
const ld PI = 3.1415926535897932;
const ll four[] = {0, 1, 0, -1, 0};
const ll eight[] = {0, 1, 1, 0, -1, -1, 1, -1, 0};
#define overload4(_1, _2, _3, _4, name, ...) name
#define rep1(n) for(ll i = 0; i < (n); ++i)
#define rep2(i, n) for(ll i = 0; i < (n); ++i)
#define rep3(i, a, b) for(ll i = (a); i < (b); ++i)
#define rep4(i, a, b, c) for(ll i = (a); i < (b); i += (c))
#define rep(...) overload4(__VA_ARGS__, rep4, rep3, rep2, rep1)(__VA_ARGS__)
#define rrep1(n) for(ll i = (n); i --> 0; )
#define rrep2(i, n) for(ll i = (n); i --> 0; )
#define rrep3(i, a, b) for(ll i = (b); i --> (a); )
#define rrep4(i, a, b, c) for(ll i = (b); (i -= (c)) >= (a); )
#define rrep(...) overload4(__VA_ARGS__, rrep4, rrep3, rrep2, rrep1)(__VA_ARGS__)
#define all(...) begin(__VA_ARGS__), end(__VA_ARGS__)
#define So(...) sort(begin(__VA_ARGS__), end(__VA_ARGS__))
#define vec(type,name,...) vector<type> name(__VA_ARGS__)
#define vv(type,name,h,...) vector<vector<type>>name(h,vector<type>(__VA_ARGS__))
#define vvv(type,name,h,w,...) vector<vector<vector<type>>>name(h,vector<vector<type>>(w,vector<type>(__VA_ARGS__)))
#define INT(...) int __VA_ARGS__; in(__VA_ARGS__)
#define LL(...) ll __VA_ARGS__; in(__VA_ARGS__)
#define ULL(...) ull __VA_ARGS__; in(__VA_ARGS__)
#define STR(...) string __VA_ARGS__; in(__VA_ARGS__)
#define CHR(...) char __VA_ARGS__; in(__VA_ARGS__)
#define DBL(...) double __VA_ARGS__; in(__VA_ARGS__)
#define LD(...) ld __VA_ARGS__; in(__VA_ARGS__)
#define VEC(type,name,size) vector<type> name(size); in(name)
#define VV(type, name, h, w) vector<vector<type>> name(h, vector<type>(w)); in(name)
template<class T> bool chmin(T &a, const T &b){ if(a > b){ a = b; return 1; } else return 0; }
template<class T> bool chmax(T &a, const T &b){ if(a < b){ a = b; return 1; } else return 0; }
template<class... T> constexpr auto min(T... a) { return min(initializer_list<common_type_t<T...>>{a...}); }
template<class... T> constexpr auto max(T... a) { return max(initializer_list<common_type_t<T...>>{a...}); }
int scan(){ return getchar(); }
void scan(int& a){ scanf("%d", &a); }
void scan(unsigned& a){ scanf("%u", &a); }
void scan(long long& a){ scanf("%lld", &a); }
void scan(unsigned long long& a){ scanf("%llu", &a); }
void scan(char& a){ do{ a = getchar(); }while(a == ' ' || a == '\n'); }
void scan(float& a){ scanf("%f", &a); }
void scan(double& a){ scanf("%lf", &a); }
void scan(long double& a){ scanf("%Lf", &a); }
void scan(vector<bool>& a){ for(unsigned i = 0; i < a.size(); i++) { int b; scan(b); a[i] = b; } }
void scan(char a[]){ scanf("%s", a); }
void scan(string& a){ cin >> a; }
template<class T> void scan(vector<T>&);
template<class T> void scan(deque<T>&);
template<class T, size_t size> void scan(array<T, size>&);
template<class T, class L> void scan(pair<T, L>&);
template<class T, size_t size> void scan(T(&)[size]);
template<class T> void scan(vector<T>& a){ for(auto& i : a) scan(i); }
template<class T> void scan(deque<T>& a){ for(auto& i : a) scan(i); }
template<class T, size_t size> void scan(array<T, size>& a){ for(auto& i : a) scan(i); }
template<class T, class L> void scan(pair<T, L>& p){ scan(p.first); scan(p.second); }
template<class T, size_t size> void scan(T (&a)[size]){ for(auto& i : a) scan(i); }
template<class T> void scan(T& a){ cin >> a; }
void in(){}
template <class Head, class... Tail> void in(Head& head, Tail&... tail){ scan(head); in(tail...); }
void print(){ putchar(' '); }
void print(bool a){ printf("%d", a); }
void print(int a){ printf("%d", a); }
void print(unsigned a){ printf("%u", a); }
void print(long long a){ printf("%lld", a); }
void print(unsigned long long a){ printf("%llu", a); }
void print(char a){ printf("%c", a); }
void print(char a[]){ printf("%s", a); }
void print(float a){ printf("%.15f", a); }
void print(double a){ printf("%.15f", a); }
void print(long double a){ printf("%.15Lf", a); }
void print(const string& a){ for(auto&& i : a) print(i); }
template<class T> void print(const vector<T>&);
template<class T, size_t size> void print(const array<T, size>&);
template<class T, class L> void print(const pair<T, L>& p);
template<class T, size_t size> void print(const T (&)[size]);
template<class T> void print(const vector<T>& a){ if(a.empty()) return; print(a[0]); for(auto i = a.begin(); ++i != a.end(); ){ putchar(' '); print(*i); } }
template<class T> void print(const deque<T>& a){ if(a.empty()) return; print(a[0]); for(auto i = a.begin(); ++i != a.end(); ){ putchar(' '); print(*i); } }
template<class T, size_t size> void print(const array<T, size>& a){ print(a[0]); for(auto i = a.begin(); ++i != a.end(); ){ putchar(' '); print(*i); } }
template<class T, class L> void print(const pair<T, L>& p){ print(p.first); putchar(' '); print(p.second); }
template<size_t size> void print(const char (&a)[size]){ for(auto&& i : a) if(i!=EOF)print(i); } //
template<class T, size_t size> void print(const T (&a)[size]){ print(a[0]); for(auto i = a; ++i != end(a); ){ putchar(' '); print(*i); } }
template<class T> void print(const T& a){ cout << a; }
int out(){ putchar('\n'); return 0; }
template<class T> int out(const T& t){ print(t); putchar('\n'); return 0; }
template<class Head, class... Tail> int out(const Head& head, const Tail&... tail){ print(head); putchar(' '); out(tail...); return 0; }

template<typename T>
struct segment_tree_2d {
    using F = function<T(T, T)>;
    int n, m;
    vector<vector<T>> node;
    F combine;
    T identity;
    segment_tree_2d(int n, int m, F combine, T identity) 
        : n(n), m(m), node(n<<1, vector<T>(m<<1, identity)), combine(combine), identity(identity) {}
    segment_tree_2d(vector<vector<T>> &v, F combine, T identity) : n(v.size()), m(v[0].size()), node(n<<1, vector<T>(m<<1, identity)), combine(combine), identity(identity) {
        for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) node[i+n][j+m] = v[i][j];
        for (int i = n; i < n<<1; i++) for (int j = m-1; j > 0; j--) node[i][j] = combine(node[i][j<<1|0], node[i][j<<1|1]);
        for (int i = n-1; i > 0; i--) for (int j = 1; j < m<<1; j++) node[i][j] = combine(node[i<<1|0][j], node[i<<1|1][j]);
    }
    T val(int i, int j) {
        assert(0 <= i && i < n);
        assert(0 <= j && j < m);
        return node[i+n][j+m];
    }
    void set(int i, int j, T x) {
        assert(0 <= i && i < n);
        assert(0 <= j && j < m);
        node[i += n][j += m] = x;
        int j2 = j;
        while (j >>= 1) node[i][j] = combine(node[i][j<<1|0], node[i][j<<1|1]);
        j = j2;
        while (i >>= 1) {
            node[i][j] = combine(node[i<<1|0][j], node[i<<1|1][j]);
            while (j >>= 1) {
                node[i][j] = combine(node[i<<1|0][j], node[i<<1|1][j]);
            }
            j = j2;
        }
    }
    // [l1, r1) * [l2, r2)
    T fold(int l1, int r1, int l2, int r2) {
        assert(0 <= l1 && l1 <= r1 && r1<= n);
        assert(0 <= l2 && l2 <= r2 && r2 <= m);
        T vl, vr;
        vl = vr = identity;
        for (l1 += n, r1 += n; l1 < r1; l1 >>= 1, r1 >>= 1) {
            if (l1 & 1) vl = combine(vl, fold_w(l1++, l2, r2));
            if (r1 & 1) vr = combine(fold_w(--r1, l2, r2), vr);
        }
        return combine(vl, vr);
    }
    T fold_w(int i, int l, int r) {
        assert(0 <= l && l <= r && r <= m);
        T vl, vr;
        vl = vr = identity;
        for (l += m, r += m; l < r; l >>= 1, r >>= 1) {
            if (l & 1) vl = combine(vl, node[i][l++]);
            if (r & 1) vr = combine(node[i][--r], vr);
        }
        return combine(vl, vr);
    }
};

int combine(int a, int b) { return min(a, b); }
int identity = INT_MAX;

int main() {
    while(1) {
        INT(r,c,q);
        if((ll)r*c > 250000) return 1;
        if(r+c+q == 0) return 0;
        VV(int,grid,r,c);
        segment_tree_2d<int> seg(grid, combine, identity);
        grid.clear();
        while(q--) {
            INT(r1,c1,r2,c2);
            cout << seg.fold(r1,r2+1,c1,c2+1) << endl;
        }
    }
}
accuracy: 0.125
time_ms: 100
memory_kb: 4364
final_rank: 20

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for (long long i = 0; i < (long long)(n); i++)
#define rrep(i,start,end) for (long long i = start;i >= (long long)(end);i--)
#define repn(i,end) for(long long i = 0; i <= (long long)(end); i++)
#define reps(i,start,end) for(long long i = start; i < (long long)(end); i++)
#define repsn(i,start,end) for(long long i = start; i <= (long long)(end); i++)
#define each(p,a) for(auto &p:a)
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef vector<long long> vll;
typedef vector<pair<long long ,long long>> vpll;
typedef vector<vector<long long>> vvll;
typedef set<ll> sll;
typedef map<long long , long long> mpll;
typedef pair<long long ,long long> pll;
typedef tuple<long long , long long , long long> tpl3;
#define LL(...) ll __VA_ARGS__; input(__VA_ARGS__)
#define LD(...) ld __VA_ARGS__; input(__VA_ARGS__)
#define Str(...) string __VA_ARGS__; input(__VA_ARGS__)
#define Ch(...) char __VA_ARGS__; input(__VA_ARGS__)
#define all(a)  (a).begin(),(a).end()
#define UNIQUE(v) v.erase( unique(v.begin(), v.end()), v.end() );
#define sz(x) (int)x.size()
// << std::fixed << std::setprecision(10)
const ll INF = 1LL << 60;
const ld EPS = 1e-9;
 
inline ll lfloor(ll x,ll m){return (x - ((x % m+ m)%m))/m;}
inline ll positive_mod(ll a,ll m){return (a % m + m)%m;}
inline ll popcnt(ull a){ return __builtin_popcountll(a);}
template<class T> bool chmin(T& a, T b){if(a > b){a = b;return true;}return false;}
template<class T> bool chmax(T& a, T b){if(a < b){a = b;return true;}return false;}
template<typename T> std::istream &operator>>(std::istream&is,std::vector<T>&v){for(T &in:v){is>>in;}return is;}
template<typename T> std::ostream &operator<<(std::ostream&os,const std::vector<T>&v){for(auto it=std::begin(v);it!=std::end(v);){os<<*it<<((++it)!=std::end(v)?" ":"");}return os;}
template<typename T1, typename T2>std::ostream &operator<< (std::ostream &os, std::pair<T1,T2> p){os << "{" << p.first << "," << p.second << "}";return os;}
template<class... T>void input(T&... a){(cin >> ... >> a);}
void print(){cout << endl;}
template<class T, class... Ts>void print(const T& a, const Ts&... b){cout << a;((cout << ' ' << b), ...);cout << endl;}
template<class T> void pspace(const T& a){ cout << a << ' ';}
void perr(){cerr << endl;}
template<class T, class... Ts>void perr(const T& a, const Ts&... b){cerr << a;((cerr << ' ' << b), ...);cerr << endl;}
void yes(bool i = true){ return print(i?"yes":"no"); }
void Yes(bool i = true){ return print(i?"Yes":"No"); }
void YES(bool i = true){ return print(i?"YES":"NO"); }
template <class T> vector<T> &operator++(vector<T> &v) {for(auto &e : v) e++;return v;}
template <class T> vector<T> operator++(vector<T> &v, signed) {auto res = v;for(auto &e : v) e++;return res;}
template <class T> vector<T> &operator--(vector<T> &v) {for(auto &e : v) e--;return v;}
template <class T> vector<T> operator--(vector<T> &v, signed) {auto res = v;for(auto &e : v) e--;return res;}
//grid探索用
vector<ll> _ta = {0,0,1,-1,1,1,-1,-1};
vector<ll> _yo = {1,-1,0,0,1,-1,1,-1};
bool isin(ll now_i,ll now_j,ll h,ll w){return (0<=now_i && now_i < h && 0 <= now_j && now_j < w);}
  
ll lpow(ll x,ll n){ll ans = 1;while(n >0){if(n & 1)ans *= x;x *= x;n >>= 1;}return ans;}
ll Modlpow(ll x,ll n,ll m){ll ans = 1;ll a = x%m;while(n >0){if(n & 1){ans *= a;ans%= m;}a *= a;a %= m;n >>= 1;}return ans;} 
const ll MOD9 = 998244353LL;
const ll MOD10 = 1000000007LL;

//verify(update & query) https://atcoder.jp/contests/abc106/submissions/52135955
//参考 https://drken1215.hatenablog.com/entry/2024/03/31/132815

template<class T>
class SegmentTree2D{
  public:
  vector<T> tree;
  ll h,w;//配列のサイズに使う
  ll hsiz,wsiz; 
  T e; //単位元 初期化に使われるやつ
  function<T(T,T)> op;
 
  SegmentTree2D(){}

  SegmentTree2D(ll _h,ll _w,function<T(T,T)> _op,T _e){
    init(_h,_w,_op,_e);
  }

  void init(ll _h,ll _w,function<T(T,T)> _op, T _e){
    h = _h;w = _w;
    op = _op;
    e = _e;
    ll i = 0;
    while((1 << i) < h){i++;}
    hsiz = 1 << i;

    ll j = 0;
    while((1 << j) < w){j++;}
    wsiz = 1 << j;
    tree.assign(hsiz * wsiz * 4,e);
  }

  ll id(ll y,ll x) const{
    return y * 2 * wsiz + x;
  }

  void build(const vector<vector<T>> &v){
    assert(h == (ll)v.size() && w == (ll)v[0].size());
    rep(i,h){
      rep(j,w){
        tree[id(i + hsiz,j + wsiz)] = v[i][j];
      }
    }
    for(ll j = wsiz;j < wsiz * 2;j++){
      for(ll i = hsiz-1;i;i--){
        tree[id(i,j)] = op(tree[id(i*2,j)],tree[id(i*2 +1,j)]);
      }
    }
    for(ll i = 0;i <hsiz * 2;i++){
      for(ll j = wsiz-1;j;j--){
        tree[id(i,j)] = op(tree[id(i,j*2)],tree[id(i,j*2+1)]);
      }
    }
  }

  void update(ll y,ll x,T v){
    assert(y >= 0 && y < h && x >= 0 && x < w);
    y += hsiz;x += wsiz;
    tree[id(y,x)] = v;
    for(ll i = y >> 1;i;i >>= 1){
      tree[id(i,x)] = op(tree[id(i * 2,x)],tree[id(i * 2 + 1,x)]);
    }
    for(;y;y >>= 1){
      for(ll j = x >> 1;j;j>>= 1){
        tree[id(y,j)] = op(tree[id(y,j * 2)],tree[id(y,j * 2 + 1)]);
      }
    }
  }

  T _query(ll y, ll xl,ll xr){
    T ret = e;
    while(xl < xr){
      if(xl & 1)ret = op(ret,tree[id(y,xl++)]);
      if(xr & 1)ret = op(tree[id(y,--xr)],ret);
      xl >>= 1;xr >>= 1;
    }
    return ret;
  }

  T query(ll yl,ll yr,ll xl,ll xr){
    assert(0 <= yl && yl <= yr && yr <= h);
    assert(0 <= xl && xl <= xr && xr <= w);
    T ret = e;
    yl += hsiz; yr += hsiz; xl += wsiz; xr += wsiz;
    while(yl < yr){
      if(yl & 1)ret = op(ret,_query(yl++,xl,xr));
      if(yr & 1)ret = op(_query(--yr,xl,xr),ret);
      yl >>= 1;yr >>= 1;
    }
    return ret;
  }

  T operator () (ll y,ll x){
    return tree[id(y + hsiz,x + wsiz)];
  }
};
 
int main(){
  ios::sync_with_stdio(false);cin.tie(nullptr);
  auto op = [](ll a,ll b){
    return min(a,b);
  };
  while(true){

    LL(r,c,q);
    if(r == 0 && c == 0 && q == 0)break;
    vvll a(r,vll(c));
    rep(i,r){
      rep(j,c){
        cin >> a[i][j];
      }
    }
    SegmentTree2D<ll> seg(r,c,op,INF);
    seg.build(a);
    rep(i,q){
      LL(r1,c1,r2,c2);
      cout << seg.query(r1,r2+1,c1,c2+1) << endl;
    }
  }
}
accuracy: 1
time_ms: 140
memory_kb: 90544
final_rank: 13

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for (long long i = 0; i < (long long)(n); i++)
#define rrep(i,start,end) for (long long i = start;i >= (long long)(end);i--)
#define repn(i,end) for(long long i = 0; i <= (long long)(end); i++)
#define reps(i,start,end) for(long long i = start; i < (long long)(end); i++)
#define repsn(i,start,end) for(long long i = start; i <= (long long)(end); i++)
#define each(p,a) for(auto &p:a)
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef vector<long long> vll;
typedef vector<pair<long long ,long long>> vpll;
typedef vector<vector<long long>> vvll;
typedef set<ll> sll;
typedef map<long long , long long> mpll;
typedef pair<long long ,long long> pll;
typedef tuple<long long , long long , long long> tpl3;
#define LL(...) ll __VA_ARGS__; input(__VA_ARGS__)
#define LD(...) ld __VA_ARGS__; input(__VA_ARGS__)
#define Str(...) string __VA_ARGS__; input(__VA_ARGS__)
#define Ch(...) char __VA_ARGS__; input(__VA_ARGS__)
#define all(a)  (a).begin(),(a).end()
#define UNIQUE(v) v.erase( unique(v.begin(), v.end()), v.end() );
#define sz(x) (int)x.size()
// << std::fixed << std::setprecision(10)
const ll INF = 1LL << 60;
const ld EPS = 1e-9;
 
inline ll lfloor(ll x,ll m){return (x - ((x % m+ m)%m))/m;}
inline ll positive_mod(ll a,ll m){return (a % m + m)%m;}
inline ll popcnt(ull a){ return __builtin_popcountll(a);}
template<class T> bool chmin(T& a, T b){if(a > b){a = b;return true;}return false;}
template<class T> bool chmax(T& a, T b){if(a < b){a = b;return true;}return false;}
template<typename T> std::istream &operator>>(std::istream&is,std::vector<T>&v){for(T &in:v){is>>in;}return is;}
template<typename T> std::ostream &operator<<(std::ostream&os,const std::vector<T>&v){for(auto it=std::begin(v);it!=std::end(v);){os<<*it<<((++it)!=std::end(v)?" ":"");}return os;}
template<typename T1, typename T2>std::ostream &operator<< (std::ostream &os, std::pair<T1,T2> p){os << "{" << p.first << "," << p.second << "}";return os;}
template<class... T>void input(T&... a){(cin >> ... >> a);}
void print(){cout << endl;}
template<class T, class... Ts>void print(const T& a, const Ts&... b){cout << a;((cout << ' ' << b), ...);cout << endl;}
template<class T> void pspace(const T& a){ cout << a << ' ';}
void perr(){cerr << endl;}
template<class T, class... Ts>void perr(const T& a, const Ts&... b){cerr << a;((cerr << ' ' << b), ...);cerr << endl;}
void yes(bool i = true){ return print(i?"yes":"no"); }
void Yes(bool i = true){ return print(i?"Yes":"No"); }
void YES(bool i = true){ return print(i?"YES":"NO"); }
template <class T> vector<T> &operator++(vector<T> &v) {for(auto &e : v) e++;return v;}
template <class T> vector<T> operator++(vector<T> &v, signed) {auto res = v;for(auto &e : v) e++;return res;}
template <class T> vector<T> &operator--(vector<T> &v) {for(auto &e : v) e--;return v;}
template <class T> vector<T> operator--(vector<T> &v, signed) {auto res = v;for(auto &e : v) e--;return res;}
//grid探索用
vector<ll> _ta = {0,0,1,-1,1,1,-1,-1};
vector<ll> _yo = {1,-1,0,0,1,-1,1,-1};
bool isin(ll now_i,ll now_j,ll h,ll w){return (0<=now_i && now_i < h && 0 <= now_j && now_j < w);}
  
ll lpow(ll x,ll n){ll ans = 1;while(n >0){if(n & 1)ans *= x;x *= x;n >>= 1;}return ans;}
ll Modlpow(ll x,ll n,ll m){ll ans = 1;ll a = x%m;while(n >0){if(n & 1){ans *= a;ans%= m;}a *= a;a %= m;n >>= 1;}return ans;} 
const ll MOD9 = 998244353LL;
const ll MOD10 = 1000000007LL;

//参考 https://drken1215.hatenablog.com/entry/2024/03/31/132815

template<class T>
class SegmentTree2D{
  public:
  vector<T> tree;
  ll h,w;//配列のサイズに使う
  ll hsiz,wsiz; 
  T e; //単位元 初期化に使われるやつ
  function<T(T,T)> op;
 
  SegmentTree2D(){}

  SegmentTree2D(ll _h,ll _w,function<T(T,T)> _op,T _e){
    init(_h,_w,_op,_e);
  }

  void init(ll _h,ll _w,function<T(T,T)> _op, T _e){
    h = _h;w = _w;
    op = _op;
    e = _e;
    ll i = 0;
    while((1 << i) < h){i++;}
    hsiz = 1 << i;

    ll j = 0;
    while((1 << j) < w){j++;}
    wsiz = 1 << j;
    tree.assign(hsiz * wsiz * 4,e);
  }

  ll id(ll y,ll x) const{
    return y * 2 * wsiz + x;
  }

  void build(const vector<vector<T>> &v){
    assert(h == (ll)v.size() && w == (ll)v[0].size());
    rep(i,h){
      rep(j,w){
        tree[id(i + hsiz,j + wsiz)] = v[i][j];
      }
    }
    for(ll j = wsiz;j < wsiz * 2;j++){
      for(ll i = hsiz-1;i;i--){
        tree[id(i,j)] = op(tree[id(i*2,j)],tree[id(i*2 +1,j)]);
      }
    }
    for(ll i = 0;i <hsiz * 2;i++){
      for(ll j = wsiz-1;j;j--){
        tree[id(i,j)] = op(tree[id(i,j*2)],tree[id(i,j*2+1)]);
      }
    }
  }

  void update(ll y,ll x,T v){
    assert(y >= 0 && y < h && x >= 0 && x < w);
    y += hsiz;x += wsiz;
    tree[id(y,x)] = v;
    for(ll i = y >> 1;i;i >>= 1){
      tree[id(i,x)] = op(tree[id(i * 2,x)],tree[id(i * 2 + 1,x)]);
    }
    for(;y;y >>= 1){
      for(ll j = x >> 1;x;x>>= 1){
        tree[id(y,j)] = op(tree[id(y,j * 2)],tree[id(y,j * 2 + 1)]);
      }
    }
  }

  T _query(ll y, ll xl,ll xr){
    T ret = e;
    while(xl < xr){
      if(xl & 1)ret = op(ret,tree[id(y,xl++)]);
      if(xr & 1)ret = op(tree[id(y,--xr)],ret);
      xl >>= 1;xr >>= 1;
    }
    return ret;
  }

  T query(ll yl,ll yr,ll xl,ll xr){
    assert(0 <= yl && yl <= yr && yr <= h);
    assert(0 <= xl && xl <= xr && xr <= w);
    T ret = e;
    yl += hsiz; yr += hsiz; xl += wsiz; xr += wsiz;
    while(yl < yr){
      if(yl & 1)ret = op(ret,_query(yl++,xl,xr));
      if(yr & 1)ret = op(_query(--yr,xl,xr),ret);
      yl >>= 1;yr >>= 1;
    }
    return ret;
  }

  T operator () (ll y,ll x){
    return tree[id(y + hsiz,x + wsiz)];
  }
};
 
int main(){
  ios::sync_with_stdio(false);cin.tie(nullptr);
  auto op = [](ll a,ll b){
    return min(a,b);
  };
  while(true){

    LL(r,c,q);
    if(r == 0 && c == 0 && q == 0)break;
    vvll a(r,vll(c));
    rep(i,r){
      rep(j,c){
        cin >> a[i][j];
      }
    }
    SegmentTree2D<ll> seg(r,c,op,INF);
    seg.build(a);
    rep(i,q){
      LL(r1,c1,r2,c2);
      cout << seg.query(r1,r2+1,c1,c2+1) << endl;
    }
  }
}
accuracy: 1
time_ms: 140
memory_kb: 90344
final_rank: 10

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for (long long i = 0; i < (long long)(n); i++)
#define rrep(i,start,end) for (long long i = start;i >= (long long)(end);i--)
#define repn(i,end) for(long long i = 0; i <= (long long)(end); i++)
#define reps(i,start,end) for(long long i = start; i < (long long)(end); i++)
#define repsn(i,start,end) for(long long i = start; i <= (long long)(end); i++)
#define each(p,a) for(auto &p:a)
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef vector<long long> vll;
typedef vector<pair<long long ,long long>> vpll;
typedef vector<vector<long long>> vvll;
typedef set<ll> sll;
typedef map<long long , long long> mpll;
typedef pair<long long ,long long> pll;
typedef tuple<long long , long long , long long> tpl3;
#define LL(...) ll __VA_ARGS__; input(__VA_ARGS__)
#define LD(...) ld __VA_ARGS__; input(__VA_ARGS__)
#define Str(...) string __VA_ARGS__; input(__VA_ARGS__)
#define Ch(...) char __VA_ARGS__; input(__VA_ARGS__)
#define all(a)  (a).begin(),(a).end()
#define UNIQUE(v) v.erase( unique(v.begin(), v.end()), v.end() );
#define sz(x) (int)x.size()
// << std::fixed << std::setprecision(10)
const ll INF = 1LL << 60;
const ld EPS = 1e-9;
 
inline ll lfloor(ll x,ll m){return (x - ((x % m+ m)%m))/m;}
inline ll positive_mod(ll a,ll m){return (a % m + m)%m;}
inline ll popcnt(ull a){ return __builtin_popcountll(a);}
template<class T> bool chmin(T& a, T b){if(a > b){a = b;return true;}return false;}
template<class T> bool chmax(T& a, T b){if(a < b){a = b;return true;}return false;}
template<typename T> std::istream &operator>>(std::istream&is,std::vector<T>&v){for(T &in:v){is>>in;}return is;}
template<typename T> std::ostream &operator<<(std::ostream&os,const std::vector<T>&v){for(auto it=std::begin(v);it!=std::end(v);){os<<*it<<((++it)!=std::end(v)?" ":"");}return os;}
template<typename T1, typename T2>std::ostream &operator<< (std::ostream &os, std::pair<T1,T2> p){os << "{" << p.first << "," << p.second << "}";return os;}
template<class... T>void input(T&... a){(cin >> ... >> a);}
void print(){cout << endl;}
template<class T, class... Ts>void print(const T& a, const Ts&... b){cout << a;((cout << ' ' << b), ...);cout << endl;}
template<class T> void pspace(const T& a){ cout << a << ' ';}
void perr(){cerr << endl;}
template<class T, class... Ts>void perr(const T& a, const Ts&... b){cerr << a;((cerr << ' ' << b), ...);cerr << endl;}
void yes(bool i = true){ return print(i?"yes":"no"); }
void Yes(bool i = true){ return print(i?"Yes":"No"); }
void YES(bool i = true){ return print(i?"YES":"NO"); }
template <class T> vector<T> &operator++(vector<T> &v) {for(auto &e : v) e++;return v;}
template <class T> vector<T> operator++(vector<T> &v, signed) {auto res = v;for(auto &e : v) e++;return res;}
template <class T> vector<T> &operator--(vector<T> &v) {for(auto &e : v) e--;return v;}
template <class T> vector<T> operator--(vector<T> &v, signed) {auto res = v;for(auto &e : v) e--;return res;}
//grid探索用
vector<ll> _ta = {0,0,1,-1,1,1,-1,-1};
vector<ll> _yo = {1,-1,0,0,1,-1,1,-1};
bool isin(ll now_i,ll now_j,ll h,ll w){return (0<=now_i && now_i < h && 0 <= now_j && now_j < w);}
  
ll lpow(ll x,ll n){ll ans = 1;while(n >0){if(n & 1)ans *= x;x *= x;n >>= 1;}return ans;}
ll Modlpow(ll x,ll n,ll m){ll ans = 1;ll a = x%m;while(n >0){if(n & 1){ans *= a;ans%= m;}a *= a;a %= m;n >>= 1;}return ans;} 
const ll MOD9 = 998244353LL;
const ll MOD10 = 1000000007LL;

//参考 https://drken1215.hatenablog.com/entry/2024/03/31/132815

template<class T>
class SegmentTree2D{
  public:
  vector<T> tree;
  ll h,w;//配列のサイズに使う
  ll hsiz,wsiz; 
  T e; //単位元 初期化に使われるやつ
  function<T(T,T)> op;
 
  SegmentTree2D(){}

  SegmentTree2D(ll _h,ll _w,function<T(T,T)> _op,T _e){
    init(_h,_w,_op,_e);
  }

  void init(ll _h,ll _w,function<T(T,T)> _op, T _e){
    h = _h;w = _w;
    op = _op;
    e = _e;
    ll i = 0;
    while((1 << i) < h){i++;}
    hsiz = 1 << i;

    ll j = 0;
    while((1 << j) < w){j++;}
    wsiz = 1 << j;
    tree.assign(hsiz * wsiz * 4,e);
  }

  ll id(ll y,ll x) const{
    return y * 2 * wsiz + x;
  }

  void build(const vector<vector<T>> &v){
    assert(h == (ll)v.size() && w == (ll)v[0].size());
    rep(i,h){
      rep(j,w){
        tree[id(i + hsiz,j + wsiz)] = v[i][j];
      }
    }
    for(ll j = wsiz;j < wsiz * 2;j++){
      for(ll i = hsiz-1;i >= 1;i--){
        tree[id(i,j)] = op(tree[id(i*2,j)],tree[id(i*2 +1,j)]);
      }
    }
    for(ll i = 0;i <hsiz * 2;i++){
      for(ll j = wsiz-1;j >= 1;j--){
        tree[id(i,j)] = op(tree[id(i,j*2)],tree[id(i,j*2+1)]);
      }
    }
  }

  void update(ll y,ll x,T v){
    assert(y >= 0 && y < h && x >= 0 && x < w);
    y += hsiz;x += wsiz;
    tree[id(y,x)] = v;
    for(ll i = y >> 1;i >= 1;i >>= 1){
      tree[id(i,x)] = op(tree[id(i * 2,x)],tree[id(i * 2 + 1,x)]);
    }
    for(;y>= 1;y >>= 1){
      for(ll j = x >> 1;x >= 1;x>>= 1){
        tree[id(y,j)] = op(tree[id(y,j * 2)],tree[id(y,j * 2 + 1)]);
      }
    }
  }

  T _query(ll y, ll xl,ll xr){
    T ret = e;
    while(xl < xr){
      if(xl & 1)ret = op(ret,tree[id(y,xl++)]);
      if(xr & 1)ret = op(tree[id(y,--xr)],ret);
      xl >>= 1;xr >>= 1;
    }
    return ret;
  }

  T query(ll yl,ll yr,ll xl,ll xr){
    assert(0 <= yl && yl <= yr && yr <= h);
    assert(0 <= xl && xl <= xr && xr <= w);
    T ret = e;
    yl += hsiz; yr += hsiz; xl += wsiz; xr += wsiz;
    while(yl < yr){
      if(yl & 1)ret = op(ret,_query(yl++,xl,xr));
      if(yr & 1)ret = op(_query(--yr,xl,xr),ret);
      yl >>= 1;yr >>= 1;
    }
    return ret;
  }

  T operator () (ll y,ll x){
    return tree[id(y + hsiz,x + wsiz)];
  }
};
 
int main(){
  ios::sync_with_stdio(false);cin.tie(nullptr);
  auto op = [](ll a,ll b){
    return min(a,b);
  };
  while(true){

    LL(r,c,q);
    if(r == 0 && c == 0 && q == 0)break;
    vvll a(r,vll(c));
    rep(i,r){
      rep(j,c){
        cin >> a[i][j];
      }
    }
    SegmentTree2D<ll> seg(r,c,op,INF);
    seg.build(a);
    // rep(i,r){
    //   rep(j,c){
    //     pspace(seg(i,j));
    //   }
    //   print();
    // }
    rep(i,q){
      LL(r1,c1,r2,c2);
      cout << seg.query(r1,r2+1,c1,c2+1) << endl;
    }
  }

  
  // SegmentTree2D<ll> seg(1001,1001,op,0);
  // rep(i,n){
  //   LL(x1,y1,x2,y2);
  //   seg.update(y1,x1,seg(y1,x1) +1);
  //   seg.update(y1,x2+1,seg(y1,x2+1) -1);
  //   seg.update(y2+1,x1,seg(y2+1,x1) -1);
  //   seg.update(y2+1,x2+1,seg(y2+1,x2+1) +1);
  // }
  // ll ans  =0;
  // rep(i,1001){
  //   rep(j,1001){
  //     if(i <= 5 && j <= 5){
  //       perr(i,j,seg.query(0,i+1,0,j+1));

  //     }
  //     chmax(ans,seg.query(0,i+1,0,j+1));
  //   }

  // }
  // cout << ans << endl;
}
accuracy: 1
time_ms: 140
memory_kb: 90372
final_rank: 11

code_snippet: /**
*    author:  shu8Cream
*    created: 2024/04/06 13:39:53
**/

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

template<class S, S(*op)(S,S), S(*e)()>
struct segtree2d {
private:
    int h,w;
    int hsize,wsize;
    vector<S> data;

    unsigned int bit_ceil(unsigned int n){
        unsigned int x = 1;
        while(x < (unsigned int)(n)) x*=2;
        return x;
    }

    int id(int r, int c) const { return r*2*wsize+c; }

    S _inner_prod(int l, int r1, int r2){
        S res = e();
        for(; r1<r2; r1>>=1, r2>>=1){
            if(r1&1) res = op(res, data[id(l,r1)]), r1++;
            if(r2&1) --r2, res = op(res, data[id(l,r2)]);
        }
        return res;
    }

public:
    segtree2d(): segtree2d(0,0){}
    segtree2d(int h, int w): h(h),w(w) {
        hsize = (int)bit_ceil((unsigned int)(h));
        wsize = (int)bit_ceil((unsigned int)(w));
        data.assign(4*hsize*wsize,e());
    }
    segtree2d(const vector<vector<S>> &v): h(int(v.size())), w(int(v[0].size())) {
        hsize = (int)bit_ceil((unsigned int)(h));
        wsize = (int)bit_ceil((unsigned int)(w));
        data = vector<S>(4*hsize*wsize,e());
        for(int i=0; i<h; i++)for(int j=0; j<w; j++) set(i,j,v[i][j]);
        build();
    }

    void set(int r, int c, S x){
        assert(0<=r&&r<h);
        assert(0<=c&&c<w);
        data[id(r+hsize,c+wsize)] = x;
    }

    void build(){
        for(int c=wsize; c<2*wsize; c++){
            for(int r=hsize-1; r; r--){
                data[id(r,c)] = op(data[id(2*r,c)], data[id(2*r+1,c)]);
            }
        }
        for(int r=0; r<2*hsize; r++){
            for(int c=wsize-1; c; c--){
                data[id(r,c)] = op(data[id(r,2*c)], data[id(r,2*c+1)]);
            }
        }
    }

    S get(int r, int c){
        assert(0<=r&&r<h);
        assert(0<=c&&c<w);
        return data[id(r+hsize,c+wsize)];
    }

    S prod(int i1, int j1, int i2, int j2) {
        assert(0<=i1 && i1<h && 0<=i2 && i2<=h);
        assert(0<=j1 && j1<w && 0<=j2 && j2<=w);
        if(i1>=i2 || j1>=j2) return e();
        S res = e();
        i1 += hsize; i2 += hsize;
        j1 += wsize; j2 += wsize;
        for(;i1<i2; i1>>=1, i2>>=1){
            if(i1&1) res = op(res,_inner_prod(i1,j1,j2)), i1++;
            if(i2&1) --i2, res = op(res,_inner_prod(i2,j1,j2));
        }
        return res;
    }

    void update(int r, int c, S x){
        r+=hsize; c+=wsize;
        data[id(r,c)] = x;
        for(int i=r>>1; r; r>>=1){
            data[id(i,c)] = op(data[id(2*i,c)], data[id(2*i+1,c)]);
        }
        for(; r; r>>=1){
            for(int j=c>>1; c; c>>=1){
                data[id(r,j)] = op(data[id(r,2*j)], data[id(r,2*j+1)]);
            }
        }
    }

    void _print(int i1, int j1, int i2, int j2){
        assert(0<=i1 && i1<h && 0<=i2 && i2<=h);
        assert(0<=j1 && j1<w && 0<=j2 && j2<=w);
        if(i1==i2 || j1==j2){
            cerr << "Area is 0" << endl;
            return;
        }
        for(int i=i1; i<i2; i++){
            for(int j=j1; j<j2; j++) cerr << data[id(i+hsize,j+wsize)] << " ";
            cerr << endl;
        }
    }
};
using S = ll;
const ll INF = 8e18;

S op(S a, S b){ return min(a,b); };
S e() { return INF; }

void AOJ1068(){
    while(1){
        int r,c,q; cin >> r >> c >> q;
        if(r==0) break;
        vector g(r,vector<S>(c));
        for(int i=0; i<r; i++)for(int j=0; j<c; j++){
            cin >> g[i][j];
        }
        segtree2d<S,op,e> seg(g);
        for(;q--;){
            int r1,c1,r2,c2;
            cin >> r1 >> c1 >> r2 >> c2;
            cout << seg.prod(r1,c1,r2+1,c2+1) << endl;
        }
    }
}

int main() {
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    cout << fixed << setprecision(15);
    AOJ1068();
}
accuracy: 1
time_ms: 140
memory_kb: 90448
final_rank: 12

code_snippet: #ifdef t9unkubj
#define _GLIBCXX_DEBUG
#include "debug.cpp"
#else
#define dbg(...) 199958
#endif

using namespace std;
#include<bits/stdc++.h>
using uint=unsigned;
using ll=long long;
using ull=unsigned long long;
using ld=long double;
using pii=pair<int,int>;
using pll=pair<ll,ll>;
template<class T>using vc=vector<T>;
template<class T>using vvc=vc<vc<T>>;
template<class T>using vvvc=vvc<vc<T>>;
using vi=vc<int>;
using vvi=vc<vi>;
using vvvi=vc<vvi>;
using vl=vc<ll>;
using vvl=vc<vl>;
using vvvl=vc<vvl>;
template<class T>using smpq=priority_queue<T,vector<T>,greater<T>>;
template<class T>using bipq=priority_queue<T>;
#define rep(i,n) for(ll i=0;i<(ll)n;i++)
#define REP(i,j,n) for(ll i=j;i<(ll)n;i++)
#define DREP(i,n,m) for(ll i=n;i>=m;i--)
#define drep(i,n) for(ll i=n-1;i>=0;i--)
#define all(x) x.begin(),x.end()
#define rall(x) x.rbegin(),x.rend()
#define mp make_pair
#define mt make_tuple
#define pb push_back
#define eb emplace_back
#define fi first
#define se second
#define is insert
void readvi(vi&a,int off=0){for(auto&x:a)cin>>x,x+=off;}
vi readvi(int n,int off=0){vi b(n);for(auto&x:b)cin>>x,x+=off;return b;}
void readvl(vl&a,int off=0){for(auto&x:a)cin>>x,x+=off;}
vl readvl(int n,int off=0){vl b(n);for(auto&x:b)cin>>x,x+=off;return b;}
template<class T,class F>bool chmin(T&x,F y){if(x>y){x=y;return 1;}return 0;}
template<class T,class F>bool chmax(T&x,F y){if(x<y){x=y;return 1;}return 0;}
void YesNo(bool b){cout<<(b?"Yes":"No")<<endl;}
template<class T>int popcount(T n){return __builtin_popcount(n);}
template<class T>T sum(vc<T>&a){return  accumulate(all(a),T(0));}
template<class T>T max(vc<T>&a){return *max_element(all(a));}
template<class T>T min(vc<T>&a){return *min_element(all(a));}
vvi readgraph(int n,int m,int off=1){vvi g(n);rep(i,m){int u,v;cin>>u>>v;u-=off,v-=off;g[u].push_back(v);g[v].push_back(u);} return g;}
vvi readtree(int n,int off=1){return readgraph(n,n-1,off);}
template<class T>vc<T>presum(vc<T>&a){vc<T>ret(a.size()+1);rep(i,a.size())ret[i+1]=ret[i]+a[i];return ret;}
template<class T,class F> pair<T,F> operator+(pair<T,F>&a,pair<T,F>&b){return mp(a.fi+b.fi,a.se+b.se);}
template<class T,class F> pair<T,F> operator-(pair<T,F>&a,pair<T,F>&b){return mp(a.fi-b.fi,a.se-b.se);}
template<class T,class F,class G> pair<T,F>& operator+=(pair<T,F>&a,G&b){a.fi+=b,b.se+=b;return a;}
template<class T,class F,class G> pair<T,F>& operator-=(pair<T,F>&a,G&b){a.fi-=b,b.se-=b;return a;}
template<class T,class F,class G> pair<T,F>& operator*=(pair<T,F>&a,G&b){a.fi*=b,b.se*=b;return a;}
template<class T,class F,class G> pair<T,F> operator+(pair<T,F>&a,G&b){return mp(a.fi+b,a.se+b);}
template<class T,class F,class G> pair<T,F> operator-(pair<T,F>&a,G&b){return mp(a.fi-b,a.se-b);}
template<class T,class F,class G> pair<T,F> operator*(pair<T,F>&a,G&b){return mp(a.fi*b,a.se*b);}
template<class T,class F>vc<T>& operator+=(vc<T>&a,F b){for(auto&v:a)v+=b;return a;}
template<class T,class F>vc<T>& operator-=(vc<T>&a,F b){for(auto&v:a)v-=b;return a;}
template<class T,class F>vc<T>& operator*=(vc<T>&a,F b){for(auto&v:a)v*=b;return a;}
template<class T>
struct seg2d{
    int h,w;
    using F=function<T(T,T)>;
    F op;
    T e;
    T**node;
    seg2d(int h,int w,F op,T e):h(h),w(w),op(op),e(e){
        h*=2,w*=2;
        node=new T*[h];
        for(int i=0;i<h;i++)node[i]=new T[w];
        for(int i=0;i<h;i++)for(int j=0;j<w;j++)node[i][j]=e;
    }
    void set(int i,int j,T x){
        node[i+=h][j+=w]=x;
        for(int j_=j>>1;j_>0;j_>>=1){
            node[i][j_]=op(node[i][j_<<1],node[i][j_<<1|1]);
        }
        while(i>>=1){
            node[i][j]=op(node[i<<1][j],node[i<<1|1][j]);
            for(int j_=j>>1;j_>0;j_>>=1){
                node[i][j_]=op(node[i<<1][j_],node[i<<1|1][j_]);
            }
        }
    }
    T prod(int h1,int w1,int h2,int w2){//[h1,w1)*[h2,w2)
        h1+=h,h2+=h,w1+=w,w2+=w;
        T res=e;
        while(h1<h2){
            if(h1&1){
                int W1=w1,W2=w2;
                while(w1<w2){
                    if(w1&1)res=op(res,node[h1][w1++]);
                    if(w2&1)res=op(res,node[h1][--w2]);
                    w1>>=1,w2>>=1;
                }
                w1=W1,w2=W2;
                h1++;
            }
            if(h2&1){
                --h2;
                int W1=w1,W2=w2;
                while(w1<w2){
                    if(w1&1)res=op(res,node[h2][w1++]);
                    if(w2&1)res=op(res,node[h2][--w2]);
                    w1>>=1,w2>>=1;
                }
                w1=W1,w2=W2;
            }
            h1>>=1,h2>>=1;
        }
        return res;
    }
    T operator()(int i,int j){
        return node[i+w][j+h];
    }
    ~seg2d(){
        for(int i=0;i<h;i++){
            delete[] node[i];
        }
        delete[] node;
    }
};
void solve(){
    cin.tie(0)->sync_with_stdio(0);
    while(1){
        int r,c,q;
        cin>>r>>c>>q;
        if(r==0&&c==0&&q==0)break;
        auto op=[](int a,int b){return min(a,b);};
        seg2d<int>seg(r,c,op,(1ll<<31)-1);
        rep(i,r)rep(j,c){
            int a;
            cin>>a;
            seg.set(i,j,a);
        }
        while(q--){
            int a,b,c,d;
            cin>>a>>b>>c>>d;
            cout<<seg.prod(a,b,c+1,d+1)<<endl;
        }
    }
}
signed main(){
    cin.tie(0)->sync_with_stdio(0);
#ifdef t9unkubj
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
    int t=1;
    //cin>>t;
    while(t--)solve();
}
accuracy: 1
time_ms: 310
memory_kb: 81116
final_rank: 9

code_snippet: #include <algorithm>
#include <array>
#include <bitset>
#include <cassert>
#include <climits>
#include <cmath>
#include <complex>
#include <deque>
#include <functional>
#include <iostream>
#include <iomanip>
#include <map>
#include <memory>
#include <numeric>
#include <optional>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#if __cplusplus >= 202002L
#include <bit>
#else
#ifdef _MSC_VER
#define countl_zero __lzcnt64
#else
#define countl_zero __builtin_clzll
#endif
#endif

#pragma warning (disable : 26451 6297 6385 4244 4267)
#ifdef _MSC_VER
#define __builtin_popcount __popcnt
#define __builtin_popcountll __popcnt64
#endif

using namespace std;
using lint = long long;
using P = pair<lint, lint>;
using Pii = pair<int, int>;

struct FastIO { FastIO() { ios::sync_with_stdio(false); cin.tie(nullptr); cout << fixed << setprecision(12);} }aaaAAAaaaAAA;

#define rep(i, n) for (remove_const<decltype(n)>::type i = 0; i < (n); ++i)
#define repe(i, n) for (remove_const<decltype(n)>::type i = 0; i <= (n); ++i)
#define rep1(i, n) for (remove_const<decltype(n)>::type i = 1; i < (n); ++i)
#define rep1e(i, n) for (remove_const<decltype(n)>::type i = 1; i <= (n); ++i)
#define repn(i, a, b) for (remove_const<decltype(a)>::type i = (a); i < (b); ++i)
#define repne(i, a, b) for (remove_const<decltype(a)>::type i = (a); i <= (b); ++i)
#define rrep(i, n) for (remove_const<decltype(n)>::type i = (n); i >= 0; --i)
#define all(vec) begin(vec), end(vec)
#define rall(vec) rbegin(vec), rend(vec)

constexpr long long Mod = /** 1000'000'007LL /*/ 998244353LL /**/;
constexpr long long Inf = 1'000'000'000'000'000'010LL;
constexpr int IntInf = 1000'000'010;
constexpr double Pi = 3.141592653589793238;
constexpr double InvPi = 0.318309886183790671;

const int di[] = { 0,1,0,-1,0 }, dj[] = { 1,0,-1,0,0 };

#if __has_include(<atcoder/all>)
#include <atcoder/all>

using namespace atcoder;
using mint = static_modint<Mod>;

template<int MOD>
inline istream& operator>>(istream& is, static_modint<MOD>& rhs) {
	long long tmp;
	is >> tmp;
	rhs = tmp;
	return is;
}
template<int ID>
inline istream& operator>>(istream& is, dynamic_modint<ID>& rhs) {
	long long tmp;
	is >> tmp;
	rhs = tmp;
	return is;
}
template<int MOD>
inline ostream& operator<<(ostream& os, const static_modint<MOD>& rhs) { return os << rhs.val(); }
template<int ID>
inline ostream& operator<<(ostream& os, const dynamic_modint<ID>& rhs) { return os << rhs.val(); }

mint lagrange_interpolation(const vector<mint>& y, mint t) {
	const int n = (int)y.size();

	mint res = 0;

	vector<mint> inv(n), fact_inv(n);

	inv[1] = 1;
	fact_inv[0] = 1;
	fact_inv[1] = 1;
	for (int i = 2; i < n; ++i) {
		inv[i] = -Mod / i * inv[Mod % i];
		fact_inv[i] = fact_inv[i - 1] * inv[i];
	}

	vector<mint> prod2(n);
	prod2.back() = 1;
	for (int i = n - 1; i > 0; --i) {
		prod2[i - 1] = (t - i) * prod2[i];
	}

	mint prod1 = 1;
	for (int i = 0; i < n; ++i) {
		mint a = y[i];
		a *= fact_inv[i] * fact_inv[n - 1 - i];
		if ((n - 1 - i) & 1) a = -a;

		res += a * prod1 * prod2[i];

		prod1 *= (t - i);
	}

	return res;
}

template<typename T>
lint inversion_number(const vector<T> vec) {
	vector<T> v = vec;
	sort(v.begin(), v.end());
	v.erase(unique(v.begin(), v.end()), v.end());

	const int n = vec.size();

	lint res = 0;

	fenwick_tree<int> b(n);
	for (int i = 0; i < n; ++i) {
		const int j = lower_bound(v.begin(), v.end(), vec[i]) - v.begin();
		res += b.sum(j + 1, n);
		b.add(j, 1);
	}

	return res;
}

// prod (a_i x + b_i)
template<typename T>
vector<mint> prod(const vector<T>& a, const vector<T>& b) {
	const size_t n = a.size();

	vector<vector<mint>> fs(n);
	for (size_t i = 0; i < n; ++i) {
		fs[i].resize(2);
		fs[i][0] = b[i];
		fs[i][1] = a[i];
	}
	for (size_t i = n; i > 1; i = (i + 1) >> 1) {
		for (size_t j = 0; j + 1 < i; j += 2) {
			fs[j >> 1] = convolution(fs[j], fs[j + 1]);
		}
		if (i & 1) fs[(i - 1) >> 1] = fs[i - 1];
	}

	return fs[0];
}
#endif

template<typename T> using prique = priority_queue<T>;
template<typename T> using prique_inv = priority_queue<T, vector<T>, greater<T>>;
template<typename T> inline istream& operator>>(istream& is, vector<T>& v) { for (auto&& e : v) is >> e; return is; }
template<typename T> inline istream& operator>>(istream& is, complex<T>& c) {
	double real, imag;
	is >> real >> imag;
	c.real(real);
	c.imag(imag);
	return is;
}
template<typename T> inline ostream& operator<<(ostream& os, const vector<T>& v) {
	for (auto itr = v.begin(), end_itr = v.end(); itr != end_itr;) {
		os << *itr;
		if (++itr != end_itr) os << " ";
	}
	return os;
}
template<typename T, typename U> inline bool chmin(T& a, const U b) { return a > b ? a = b, true : false; }
template<typename T, typename U> inline bool chmax(T& a, const U b) { return a < b ? a = b, true : false; }
template<typename T, typename U> inline istream& operator>>(istream& is, pair<T, U>& rhs) { return is >> rhs.first >> rhs.second; }
template<typename T, typename U> inline ostream& operator<<(ostream& os, const pair<T, U>& rhs) { return os << "{" << rhs.first << ", " << rhs.second << "}"; }
template<typename T, typename U, class Pr> inline int getid(const vector<T>& v, const U& value, Pr pred) { return lower_bound(v.begin(), v.end(), value, pred) - v.begin(); }
template<typename T, typename U> inline int getid(const vector<T>& v, const U& value) { return getid(v, value, less<>{}); }

template<typename T> T gcd(const vector<T>& vec) {
	T res = vec.front();
	for (T e : vec) {
		res = gcd(res, e);
		if (res == 1) return 1;
	}
	return res;
}
template<typename T> T gcd(initializer_list<T> init) {
	auto first = init.begin(), last = init.end();
	T res = *(first++);
	for (auto itr = first; itr != last; ++itr) {
		res = gcd(res, *itr);
		if (res == 1) return 1;
	}
	return res;
}
template<typename T> T lcm(const vector<T>& vec) {
	T res = vec.front();
	for (T e : vec) res = lcm(res, e);
	return res;
}
template<typename T> T lcm(initializer_list<T> init) {
	auto first = init.begin(), last = init.end();
	T res = *(first++);
	for (auto itr = first; itr != last; ++itr) {
		res = lcm(res, *itr);
	}
	return res;
}

inline void YesNo(bool b) { printf(b ? "Yes\n" : "No\n"); }

template<typename T>
T rand(T l, T r) {
	static mt19937 mt(random_device{}());
	if constexpr (is_integral_v<T>) {
		uniform_int_distribution<T> dist(l, r);
		return dist(mt);
	}
	else if constexpr (is_floating_point_v<T>) {
		uniform_real_distribution<T> dist(l, r);
		return dist(mt);
	}
}

bool is_prime(lint x) {
	for (lint i = 2; i * i <= x; ++i) {
		if (x % i == 0) return false;
	}
	return 1 < x;
}

vector<lint> divisors(lint n) {
	vector<lint> res;
	for (lint x = 1; x * x <= n; ++x) {
		if (n % x == 0) {
			res.push_back(x);
			if (x * x != n) res.push_back(n / x);
		}
	}
	return res;
}

lint phi(lint n) {
	lint r = n;
	for (lint i = 2; i * i <= n; ++i) {
		if (n % i == 0) {
			r -= r / i;
			while (n % i == 0) n /= i;
		}
	}
	if (n > 1) r -= r / n;
	return r;
}

lint floor_sqrt(lint n) {
	if (n == 0 || n == 1) return n;
	lint x0 = 1LL << ((65 - countl_zero(static_cast<uint64_t>(n))) >> 1);
	lint x1 = (x0 + n / x0) >> 1;
	while (x1 < x0) {
		x0 = x1;
		x1 = (x0 + n / x0) >> 1;
	}
	return x0;
}
lint ceil_sqrt(lint n) {
	const lint f = floor_sqrt(n);
	if (f * f == n) return f;
	return f + 1;
}

template<typename T>
constexpr bool is_intersect(T l1, T r1, T l2, T r2) {
	return l1 <= r2 && l2 <= r1;
}

lint modinv(lint a, lint m = Mod) {
	lint b = m, u = 1, v = 0;
	while (b != 0) {
		lint t = a / b;
		a -= t * b; swap(a, b);
		u -= t * v; swap(u, v);
	}
	u %= m;
	if (u < 0) u += m;
	return u;
}
lint modpow(lint x, lint n, lint m = Mod) {
	if (m == 1) return 0;
	lint res = 1;
	x %= m;
	while (n > 0) {
		if (n & 1) res = res * x % m;
		x = x * x % m;
		n >>= 1;
	}
	return res;
}
lint intpow(lint x, lint n) {
	lint res = 1;
	while (n > 0) {
		if (n & 1) res *= x;
		x *= x;
		n >>= 1;
	}
	return res;
}

template<typename T>
class Binomial {
private:
	vector<T> fact, inv, fact_inv;

public:
	explicit Binomial() = default;

	void build(int n) {
		fact.resize(n + 1);
		inv.resize(n + 1);
		fact_inv.resize(n + 1);

		fact[0] = fact[1] = 1;
		fact_inv[0] = fact_inv[1] = 1;
		inv[1] = 1;

		for (int i = 2; i <= n; ++i) {
			fact[i] = i * fact[i - 1];
			inv[i] = Mod - Mod / i * inv[Mod % i];
			fact_inv[i] = fact_inv[i - 1] * inv[i];
		}
	}

	T comb(int n, int r) const {
		if (n < 0 || r < 0 || n < r) return 0;
		if (r == 0 || r == n) return 1;
		return fact[n] * fact_inv[n - r] * fact_inv[r];
	}

	T perm(int n, int r) const {
		if (n < 0 || r < 0 || n < r) return 0;
		return fact[n] * fact_inv[n - r];
	}

	T multi(int n, int r) const {
		if (n == 0 && r == 0) return 1;
		if (n < 0 || r < 0) return 0;
		return r == 0 ? 1 : comb(n + r - 1, r);
	}
};

template<typename T>
vector<T> compressed(vector<T> v) {
	sort(v.begin(), v.end());
	v.erase(unique(v.begin(), v.end()), v.end());
	return v;
}

template<typename T>
vector<int> compressed_index(vector<T> v) {
	const int n = v.size();
	const auto c = compressed(v);
	vector<int> res(n);
	for (int i = 0; i < n; ++i) {
		res[i] = lower_bound(all(c), v[i]) - c.begin();
	}
	return res;
}

// { value, count }
template<typename T>
pair<vector<T>, vector<int>> compressed_pair(vector<T> v) {
	size_t n = v.size();
	sort(all(v));
	vector<T> cnt, val;
	cnt.reserve(n); val.reserve(n);
	int now_cnt = 1;
	for (size_t i = 1; i < n; ++i) {
		if (v[i - 1] != v[i]) {
			cnt.push_back(now_cnt);
			val.push_back(v[i - 1]);
			now_cnt = 1;
		}
		else ++now_cnt;
	}
	cnt.push_back(now_cnt);
	val.push_back(v.back());

	return { val, cnt };
}

class Factring {
private:

	const lint max_n;
	vector<lint> sieve;

public:

	explicit Factring(lint max_n)
		: max_n(max_n)
		, sieve(max_n + 1)
	{
		iota(sieve.begin(), sieve.end(), 0);

		for (lint i = 2; i * i <= max_n; ++i) {
			if (sieve[i] < i) continue;

			for (lint j = i * i; j <= max_n; j += i) {
				if (sieve[j] == j) sieve[j] = i;
			}
		}
	}

	unordered_map<lint, int> calc(lint x) const {
		unordered_map<lint, int> res;
		while (x > 1) {
			++res[sieve[x]];
			x /= sieve[x];
		}
		return res;
	}
};

struct UnionFind {
	int n;
	vector<int> par, rank, siz, es;
	int c;

	UnionFind() = default;

	explicit UnionFind(int _n)
		: n(_n)
		, par(_n)
		, rank(_n)
		, siz(_n, 1)
		, es(_n)
		, c(_n)
	{
		iota(par.begin(), par.end(), 0);
	}

	int root(int x) {
		while (par[x] != x) {
			x = par[x] = par[par[x]];
		}

		return x;
	}

	bool same(int x, int y) { return root(x) == root(y); }

	void unite(int x, int y) {
		x = root(x); y = root(y);
		if (x == y) ++es[x];
		else {
			c--;
			if (rank[x] < rank[y]) {
				par[x] = y;
				siz[y] += siz[x];
				es[y] += es[x] + 1;
			}
			else {
				par[y] = x;
				if (rank[x] == rank[y]) ++rank[x];
				siz[x] += siz[y];
				es[x] += es[y] + 1;
			}
		}
	}

	int count(int x) { return siz[root(x)]; }

	vector<vector<int>> groups() {
		vector<int> roots(n), group_size(n);

		for (int i = 0; i < n; ++i) {
			roots[i] = root(i);
			++group_size[roots[i]];
		}

		vector<vector<int>> res(n);

		for (int i = 0; i < n; ++i) {
			res.reserve(group_size[i]);
		}

		for (int i = 0; i < n; ++i) {
			res[roots[i]].push_back(i);
		}

		res.erase(
			remove_if(res.begin(), res.end(),
				[](const vector<int>& v) { return v.empty(); }),
			res.end()
		);

		return res;
	}
};

template<typename T>
class CumulativeSum2D {
private:

	vector<vector<T>> dat;

public:

	CumulativeSum2D() = default;

	explicit CumulativeSum2D(size_t n) : dat(n + 1, vector<T>(n + 1)) {}

	CumulativeSum2D(size_t h, size_t w) : dat(h + 1, vector<T>(w + 1)) {}

	CumulativeSum2D(const vector<vector<T>>& vec) {
		const size_t h = vec.size(), w = vec.front().size();

		dat.resize(h + 1, vector<T>(w + 1));

		for (size_t i = 0; i < h; ++i) {
			for (size_t j = 0; j < w; ++j) {
				dat[i + 1][j + 1] = dat[i][j + 1] + dat[i + 1][j] - dat[i][j] + vec[i][j];
			}
		}
	}

	void add(int h, int w, int v) {
		dat[h + 1][w + 1] += v;
	}

	void build() {
		const size_t h = dat.size() - 1, w = dat.front().size() - 1;
		for (size_t i = 0; i < h; ++i) {
			for (size_t j = 0; j < w; ++j) {
				dat[i + 1][j + 1] = dat[i][j + 1] + dat[i + 1][j] - dat[i][j];
			}
		}
	}

	// [0, h) x [0, w)
	T sum(int h, int w) const {
		return sum(0, 0, h, w);
	}

	// [h1, h2) x [w1, w2)
	T sum(int h1, int w1, int h2, int w2) const {
		return dat[h2][w2] - dat[h1][w2] - dat[h2][w1] + dat[h1][w1];
	}
};

template<typename T>
class BinaryIndexedTree {
private:

	int n;
	vector<T> dat;

public:
	BinaryIndexedTree() = default;

	explicit BinaryIndexedTree(const int size)
		: n(size)
		, dat(size + 1) {}

	explicit BinaryIndexedTree(const vector<T>& vec)
		: n(vec.size())
		, dat(n + 1)
	{
		for (int i = 0; i < n; ++i) dat[i + 1] = vec[i];
		for (int i = 1; i <= n; ++i) {
			const int j = i + (i & -i);
			if (j <= n) dat[j] += dat[i];
		}
	}

	// 0-indexed
	void add(const int a, const T v) {
		for (int x = a + 1; x <= n; x += (x & -x)) dat[x] += v;
	}

	// 0-indexed
	void set(const int a, const T v) {
		add(a, v - get(a));
	}

	void reset() { fill(dat.begin(), dat.end(), T(0)); }

	// [0, a)
	T sum(const int a) const {
		T res = 0;
		for (int x = a; x > 0; x -= x & -x) res += dat[x];
		return res;
	}

	// [a, b)
	T sum(const int a, const int b) const { return sum(b) - sum(a); }

	T get(const int i) const { return sum(i, i + 1); }

	// min i s.t. sum(i) >= w
	int lower_bound(T w) const {
		int x = 0, r = 1;
		while (r < n) r <<= 1;
		for (int i = r; i > 0; i >>= 1) {
			if (x + i <= n && dat[x + i] < w) {
				w -= dat[x + i];
				x += i;
			}
		}
		return x + 1;
	}
	// min i s.t. sum(i) > w
	int upper_bound(T w) const {
		int x = 0, r = 1;
		while (r < n) r <<= 1;
		for (int i = r; i > 0; i >>= 1) {
			if (x + i <= n && dat[x + i] <= w) {
				w -= dat[x + i];
				x += i;
			}
		}
		return x + 1;
	}
};

struct Point {
	lint x, y;

	Point() = default;
	constexpr Point(lint x_, lint y_) : x(x_), y(y_) {}

	constexpr bool operator==(const Point& p) const { return x == p.x && y == p.y; }
	constexpr bool operator<(const Point& p) const {
		if (x != p.x) return x < p.x;
		return y < p.y;
	}

	constexpr Point operator+() const { return *this; }
	constexpr Point operator-() const { return { -x, -y }; }
	constexpr Point operator+(const Point& p) const { return { x + p.x, y + p.y }; }
	constexpr Point operator-(const Point& p) const { return { x - p.x, y - p.y }; }
	constexpr Point operator*(lint s) const { return { x * s, y * s }; }
	constexpr Point& operator+=(const Point& p) {
		x += p.x; y += p.y;
		return *this;
	}
	constexpr Point& operator-=(const Point& p) {
		x -= p.x; y -= p.y;
		return *this;
	}

	constexpr lint dot(const Point& p) const { return x * p.x + y * p.y; }
	constexpr lint cross(const Point& p) const { return x * p.y - y * p.x; }

	constexpr lint lengthSq() const { return x * x + y * y; }
	double length() const { return hypot(x, y); }
	constexpr lint distanceSq(const Point& p) const { return (*this - p).lengthSq(); }
	double distance(const Point& p) const { return (*this - p).length(); }

	friend constexpr Point operator*(lint s, const Point& p) { return p * s; }
	friend istream& operator>>(istream& is, Point& p) { return is >> p.x >> p.y; }
	friend ostream& operator<<(ostream& os, const Point& p) { return os << "(" << p.x << "," << p.y << ")"; }
};

template<typename T, typename U>
T nearest_value(const vector<T>& v, const U& value) {
	auto itr = lower_bound(v.begin(), v.end(), value);
	if (itr == v.begin()) return *itr;
	if (itr == v.end()) return *prev(itr);
	return min(*itr - value, value - *prev(itr)) + value;
}

template<class S, S (*op)(S, S), S (*e)()>
class SegmentTree2D {
public:
	SegmentTree2D(int _h, int _w) : SegmentTree2D(vector(_h, vector(_w, e()))) {}

	SegmentTree2D(vector<vector<S>> a) {
		int sizH = (int)(a.size()), sizW = (int)(a[0].size());
		logH = ceil_log2(sizH), logW = ceil_log2(sizW);
		h = (1 << logH), w = (1 << logW);

		dat.resize((2 * w) * (2 * h), e());
		for (int i = 0; i < sizH; ++i) {
			for (int j = 0; j < sizW; ++j) {
				get(i + h, j + w) = a[i][j];
			}
		}
		for (int i = 0; i < h; ++i) {
			for (int j = w - 1; j > 0; --j) {
				updateW(i + h, j);
			}
		}
		for (int j = 1; j < 2 * w; ++j) {
			for (int k = h - 1; k > 0; --k) {
				updateH(j, k);
			}
		}
	}

	void set(int i, int j, S x) {
		i += h; j += w;
		get(i, j) = x;
		for (j >>= 1; j > 0; j >>= 1) {
			updateW(i, j);
			for (int k = (i >>= 1); k > 0; k >>= 1) {
				updateH(j, k);
			}
		}
	}

	S prod(int i0, int j0, int i1, int j1) {
		i0 += h; i1 += h;
		S sl = e(), sr = e();
		while (i0 < i1) {
			if (i0 & 1) sl = op(sl, prodW(i0++, j0, j1));
			if (i1 & 1) sr = op(prodW(--i1, j0, j1), sr);
			i0 >>= 1; i1 >>= 1;
		}
		return op(sl, sr);
	}

	S at(int i, int j) { return get(i + h, j + w); }

private:
	int h, w, logH, logW;
	vector<S> dat;

	int ceil_log2(int x) {
		int res = 0;
		while ((1 << res) < x) ++res;
		return res;
	}

	S& get(int i, int j) { return dat[(2 * w) * i + j]; }

	void updateW(int i, int j) {
		get(i, j) = op(get(i, 2 * j), get(i, 2 * j + 1));
	}
	void updateH(int j, int k) {
		get(k, j) = op(get(2 * k, j), get(2 * k + 1, j));
	}

	S prodW(int k, int l, int r) {
		l += w; r += w;
		S sl = e(), sr = e();
		while (l < r) {
			if (l & 1) sl = op(sl, get(k, l++));
			if (r & 1) sr = op(get(k, --r), sr);
			l >>= 1; r >>= 1;
		}
		return op(sl, sr);
	}
};

int op(int x, int y) { return min(x, y); }
int e() { return INT_MAX; }

int main() {
	while (true) {
		int r, c, q;
		cin >> r >> c >> q;

		if (r == 0 && c == 0 && q == 0) break;

		vector a(r, vector<int>(c));
		rep(i, r) {
			rep(j, c) {
				cin >> a[i][j];
			}
		}

		SegmentTree2D<int, op, e> seg2d(a);

		while (q--) {
			int r1, c1, r2, c2;
			cin >> r1 >> c1 >> r2 >> c2;
			cout << seg2d.prod(r1, c1, r2 + 1, c2 + 1) << "\n";
		}
	}
}
accuracy: 1
time_ms: 140
memory_kb: 128792
final_rank: 15

code_snippet: #include <iostream>
#include <vector>
#include <algorithm>
#include <map>
#include <queue>
#include <set>
#include <iomanip>
using namespace std;
typedef long long ll;
#define rep(i, n) for(int i = 0; i < (n); i++)

template<class T>
using vi = vector<T>;

template<class T>
using vii = vector<vi<T>>;

template<class T>
using viii = vector<vii<T>>;

template<class T>
struct tdsegtree {
    int n, m;
    vector<vector<T>> d;
    const T e = 1e18;

    tdsegtree(int n_ = 1, int m_ = 1) {
        n = 1, m = 1;
        while (n < n_) n <<= 1;
        while (m < m_) m <<= 1;
        d.resize(2 * n - 1, vector<T>(2 * m - 1));
    }

    T op(T x, T y) { return min(x, y); }

    void add(int i, int j, T x) {
        int idxi = i + n - 1;
        int idxj = j + m - 1;
        d[idxi][idxj] += x;

        while (idxi) {
            idxi = (idxi - 1) / 2;
            d[idxi][idxj] = op(d[2 * idxi + 1][idxj], d[2 * idxi + 2][idxj]);
        }

        idxi = i + n - 1;
        while (idxj) {
            idxj = (idxj - 1) / 2;
            d[idxi][idxj] = op(d[idxi][2 * idxj + 1], d[idxi][2 * idxj + 2]);
        }

        while (idxi) {
            idxi = (idxi - 1) / 2;
            idxj = j + m - 1;
            while (idxj) {
                idxj = (idxj - 1) / 2;
                d[idxi][idxj] = op(d[idxi][2 * idxj + 1], d[idxi][2 * idxj + 2]);
            }
        }
    }

    void update(int i, int j, T x) {
        int idxi = i + n - 1;
        int idxj = j + m - 1;
        d[idxi][idxj] = x;
        
        while (idxi) {
            idxi = (idxi - 1) / 2;
            d[idxi][idxj] = op(d[2 * idxi + 1][idxj], d[2 * idxi + 2][idxj]);
        }

        idxi = i + n - 1;
        while (idxj) {
            idxj = (idxj - 1) / 2;
            d[idxi][idxj] = op(d[idxi][2 * idxj + 1], d[idxi][2 * idxj + 2]);
        }

        while (idxi) {
            idxi = (idxi - 1) / 2;
            idxj = j + m - 1;
            while (idxj) {
                idxj = (idxj - 1) / 2;
                d[idxi][idxj] = op(d[idxi][2 * idxj + 1], d[idxi][2 * idxj + 2]);
            }            
        }
    }

    T get(int x1, int y1, int x2, int y2) {
        return get_sub(x1, x2, y1, y2, 0, 0, n, 0, 0, m);
    }

    T get_sub(int li, int ri, int lj, int rj, int idxi, int oki, int ngi, int idxj, int okj, int ngj) {
        if (ngi <= li || ri <= oki || ngj <= lj || rj <= okj) return e;
        if (li <= oki && ngi <= ri) {
            if (lj <= okj && ngj <= rj) return d[idxi][idxj];
            int midj = (okj + ngj) / 2;
            T vl = get_sub(li, ri, lj, rj, idxi, oki, ngi, 2 * idxj + 1, okj, midj);
            T vr = get_sub(li, ri, lj, rj, idxi, oki, ngi, 2 * idxj + 2, midj, ngj);
            return op(vl, vr);
        }
        int midi = (oki + ngi) / 2;
        T vl = get_sub(li, ri, lj, rj, 2 * idxi + 1, oki, midi, idxj, okj, ngj);
        T vr = get_sub(li, ri, lj, rj, 2 * idxi + 2, midi, ngi, idxj, okj, ngj);
        return op(vl, vr);
    }
};


void solve() {

}

int main()
{
    int r, c, q;
    int r1, c1, r2, c2;
    ll g;
    while (cin >> r >> c >> q) {
        if ((ll)r * c * q == 0) break;

        tdsegtree<ll> tdseg(r, c);
        rep(i, r) rep(j, c) {
            cin >> g;
            tdseg.update(i, j, g);
        }
        while (q--) {
            cin >> r1 >> c1 >> r2 >> c2;
            cout << tdseg.get(r1, c1, r2 + 1, c2 + 1) << endl;;
        }
    }
    
    
    return 0;
}
accuracy: 1
time_ms: 460
memory_kb: 117636
final_rank: 16

code_snippet: #line 2 "/Users/noya2/Desktop/Noya2_library/template/template.hpp"
using namespace std;

#include<bits/stdc++.h>
#line 1 "/Users/noya2/Desktop/Noya2_library/template/inout_old.hpp"
namespace noya2 {

template <typename T, typename U>
ostream &operator<<(ostream &os, const pair<T, U> &p){
    os << p.first << " " << p.second;
    return os;
}
template <typename T, typename U>
istream &operator>>(istream &is, pair<T, U> &p){
    is >> p.first >> p.second;
    return is;
}

template <typename T>
ostream &operator<<(ostream &os, const vector<T> &v){
    int s = (int)v.size();
    for (int i = 0; i < s; i++) os << (i ? " " : "") << v[i];
    return os;
}
template <typename T>
istream &operator>>(istream &is, vector<T> &v){
    for (auto &x : v) is >> x;
    return is;
}

void in() {}
template <typename T, class... U>
void in(T &t, U &...u){
    cin >> t;
    in(u...);
}

void out() { cout << "\n"; }
template <typename T, class... U, char sep = ' '>
void out(const T &t, const U &...u){
    cout << t;
    if (sizeof...(u)) cout << sep;
    out(u...);
}

template<typename T>
void out(const vector<vector<T>> &vv){
    int s = (int)vv.size();
    for (int i = 0; i < s; i++) out(vv[i]);
}

struct IoSetup {
    IoSetup(){
        cin.tie(nullptr);
        ios::sync_with_stdio(false);
        cout << fixed << setprecision(15);
        cerr << fixed << setprecision(7);
    }
} iosetup_noya2;

} // namespace noya2
#line 1 "/Users/noya2/Desktop/Noya2_library/template/const.hpp"
namespace noya2{

const int iinf = 1'000'000'007;
const long long linf = 2'000'000'000'000'000'000LL;
const long long mod998 =  998244353;
const long long mod107 = 1000000007;
const long double pi = 3.14159265358979323;
const vector<int> dx = {0,1,0,-1,1,1,-1,-1};
const vector<int> dy = {1,0,-1,0,1,-1,-1,1};
const string ALP = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const string alp = "abcdefghijklmnopqrstuvwxyz";
const string NUM = "0123456789";

void yes(){ cout << "Yes\n"; }
void no(){ cout << "No\n"; }
void YES(){ cout << "YES\n"; }
void NO(){ cout << "NO\n"; }
void yn(bool t){ t ? yes() : no(); }
void YN(bool t){ t ? YES() : NO(); }

} // namespace noya2
#line 1 "/Users/noya2/Desktop/Noya2_library/template/utils.hpp"
namespace noya2{

unsigned long long inner_binary_gcd(unsigned long long a, unsigned long long b){
    if (a == 0 || b == 0) return a + b;
    int n = __builtin_ctzll(a); a >>= n;
    int m = __builtin_ctzll(b); b >>= m;
    while (a != b) {
        int mm = __builtin_ctzll(a - b);
        bool f = a > b;
        unsigned long long c = f ? a : b;
        b = f ? b : a;
        a = (c - b) >> mm;
    }
    return a << min(n, m);
}

template<typename T> T gcd_fast(T a, T b){ return static_cast<T>(inner_binary_gcd(abs(a),abs(b))); }

long long sqrt_fast(long long n) {
    if (n <= 0) return 0;
    long long x = sqrt(n);
    while ((x + 1) * (x + 1) <= n) x++;
    while (x * x > n) x--;
    return x;
}

template<typename T> T floor_div(const T n, const T d) {
    assert(d != 0);
    return n / d - static_cast<T>((n ^ d) < 0 && n % d != 0);
}

template<typename T> T ceil_div(const T n, const T d) {
    assert(d != 0);
    return n / d + static_cast<T>((n ^ d) >= 0 && n % d != 0);
}

template<typename T> void uniq(vector<T> &v){
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());
}

template <typename T, typename U> inline bool chmin(T &x, U y) { return (y < x) ? (x = y, true) : false; }

template <typename T, typename U> inline bool chmax(T &x, U y) { return (x < y) ? (x = y, true) : false; }

template<typename T> inline bool range(T l, T x, T r){ return l <= x && x < r; }

} // namespace noya2
#line 8 "/Users/noya2/Desktop/Noya2_library/template/template.hpp"

#define rep(i,n) for (int i = 0; i < (int)(n); i++)
#define repp(i,m,n) for (int i = (m); i < (int)(n); i++)
#define reb(i,n) for (int i = (int)(n-1); i >= 0; i--)
#define all(v) (v).begin(),(v).end()

using ll = long long;
using ld = long double;
using uint = unsigned int;
using ull = unsigned long long;
using pii = pair<int,int>;
using pll = pair<ll,ll>;
using pil = pair<int,ll>;
using pli = pair<ll,int>;

namespace noya2{

/*　~ (. _________ . /)　*/

}

using namespace noya2;


#line 2 "c.cpp"

#line 2 "/Users/noya2/Desktop/Noya2_library/data_structure/segment_tree_2d.hpp"

#line 4 "/Users/noya2/Desktop/Noya2_library/data_structure/segment_tree_2d.hpp"

namespace noya2{

template<class S, S(*op)(S, S), S(*e)()>
struct segtree_2d {
    int h, w;
    segtree_2d (int h_ = 0, int w_ = 0) : segtree_2d(std::vector<std::vector<S>>(h_,vector<S>(w_,e()))) {}
    segtree_2d (const std::vector<std::vector<S>> &vec){
        assert(!vec.empty());
        int h_ = vec.size(); h = 1; while(h < h_) h <<= 1;
        int w_ = vec[0].size(); w = 1; while(w < w_) w <<= 1;
        d.assign(h*w*4,e());
        for (int i = 0; i < (int)(vec.size()); i++) for (int j = 0; j < (int)(vec[i].size()); j++) d[id(i+h,j+w)] = vec[i][j];
        for (int i = 0; i < h; i++) for (int j = w-1; j > 0; j--) update_y(i+h,j);
        for (int i = h-1; i > 0; i--) for (int j = 1; j < 2*w; j++) update_x(i,j);
    }
    void assign(int p, int q, S v){
        d[id(p+h,q+w)] = v;
    }
    void set(int p, int q, S v){
        p += h, q += w;
        d[id(p,q)] = v;
        for (int j = q>>1; j > 0; j >>= 1) update_y(p,j);
        for ( ; q > 0; q >>= 1) for (int i = p>>1; i > 0; i >>= 1) update_x(i,q);
    }
    S prod(int lp, int rp, int lq, int rq){
        if (lp >= rp || lq >= rq) return e();
        S res = e();
        lp += h, rp += h, lq += w, rq += w;
        for ( ; lp < rp; lp >>= 1, rp >>= 1){
            if (lp & 1) res = op(res,inner_prod(lp++,lq,rq));
            if (rp & 1) res = op(res,inner_prod(--rp,lq,rq));
        }
        return res;
    }
    S get(int p, int q){
        p += h, q += w;
        return d[id(p,q)];
    }
    int id(int p, int q){ return p * 2 * w + q; }
    void update_x(int p, int q){ d[id(p,q)] = op(d[id(2*p,q)],d[id(2*p+1,q)]); }
    void update_y(int p, int q){ d[id(p,q)] = op(d[id(p,2*q)],d[id(p,2*q+1)]); }
    S inner_prod(int p, int lq, int rq){
        S res = e();
        for ( ; lq < rq; lq >>= 1, rq >>= 1){
            if (lq & 1) res = op(res,d[id(p,lq++)]);
            if (rq & 1) res = op(res,d[id(p,--rq)]);
        }
        return res;
    }
    std::vector<S> d;
};

} // namespace noya2
#line 4 "c.cpp"

int op(int a, int b){
    return min(a,b);
}
int e(){
    return numeric_limits<int>::max();
}

void solve1(int h, int w, int q){
    vector<vector<int>> a(h,vector<int>(w)); in(a);
    segtree_2d<int,op,e> seg(a);
    while (q--){
        int lx, rx, ly, ry; in(lx,ly,rx,ry); rx++, ry++;
        out(seg.prod(lx,rx,ly,ry));
    }
}

void solve(){
    while(true){
        int h, w, q; in(h,w,q);
        if (h == 0) break;
        solve1(h,w,q);
    }
}

int main(){
    int t = 1; //in(t);
    while (t--) { solve(); }
}
accuracy: 1
time_ms: 90
memory_kb: 73992
final_rank: 4

code_snippet: #line 1 "a.cpp"
#include <algorithm>
#include <bitset>
#include <cassert>
#include <chrono>
#include <climits>
#include <cmath>
#include <complex>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <map>
#include <memory>
#include <numeric>
#include <optional>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

/* macro */

#define rep(i, a, n) for (int i = (int)(a); i < (int)(n); i++)
#define rrep(i, a, n) for (int i = ((int)(n)-1); i >= (int)(a); i--)
#define Rep(i, a, n) for (i64 i = (i64)(a); i < (i64)(n); i++)
#define RRep(i, a, n) for (i64 i = ((i64)(n)-i64(1)); i >= (i64)(a); i--)
#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()

/* macro end */

/* template */

namespace ebi {

#ifdef LOCAL
#define debug(...)                                                      \
    std::cerr << "LINE: " << __LINE__ << "  [" << #__VA_ARGS__ << "]:", \
        debug_out(__VA_ARGS__)
#else
#define debug(...)
#endif

void debug_out() {
    std::cerr << std::endl;
}

template <typename Head, typename... Tail> void debug_out(Head h, Tail... t) {
    std::cerr << " " << h;
    if (sizeof...(t) > 0) std::cerr << " :";
    debug_out(t...);
}

template <typename T1, typename T2>
std::ostream &operator<<(std::ostream &os, const std::pair<T1, T2> &pa) {
    return os << pa.first << " " << pa.second;
}

template <typename T1, typename T2>
std::istream &operator>>(std::istream &os, std::pair<T1, T2> &pa) {
    return os >> pa.first >> pa.second;
}

template <typename T>
std::ostream &operator<<(std::ostream &os, const std::vector<T> &vec) {
    for (std::size_t i = 0; i < vec.size(); i++)
        os << vec[i] << (i + 1 == vec.size() ? "" : " ");
    return os;
}

template <typename T>
std::istream &operator>>(std::istream &os, std::vector<T> &vec) {
    for (T &e : vec) std::cin >> e;
    return os;
}

template <typename T>
std::ostream &operator<<(std::ostream &os, const std::optional<T> &opt) {
    if (opt) {
        os << opt.value();
    } else {
        os << "invalid value";
    }
    return os;
}

using std::size_t;
using i32 = std::int32_t;
using u32 = std::uint32_t;
using i64 = std::int64_t;
using u64 = std::uint64_t;
using i128 = __int128_t;
using u128 = __uint128_t;

template <class T> inline bool chmin(T &a, T b) {
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}

template <class T> inline bool chmax(T &a, T b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}

template <class T> T pow(T x, i64 n) {
    T res = 1;
    while (n > 0) {
        if (n & 1) res = res * x;
        x = x * x;
        n >>= 1;
    }
    return res;
}

template <class T> struct Edge {
    int to;
    T cost;
    Edge(int _to, T _cost = 1) : to(_to), cost(_cost) {}
};

template <class T> struct Graph : std::vector<std::vector<Edge<T>>> {
    using std::vector<std::vector<Edge<T>>>::vector;
    void add_edge(int u, int v, T w, bool directed = false) {
        (*this)[u].emplace_back(v, w);
        if (directed) return;
        (*this)[v].emplace_back(u, w);
    }
};

struct graph : std::vector<std::vector<int>> {
    using std::vector<std::vector<int>>::vector;
    void add_edge(int u, int v, bool directed = false) {
        (*this)[u].emplace_back(v);
        if (directed) return;
        (*this)[v].emplace_back(u);
    }
};

constexpr i64 LNF = std::numeric_limits<i64>::max() / 4;

constexpr int INF = std::numeric_limits<int>::max() / 2;

const std::vector<int> dy = {1, 0, -1, 0, 1, 1, -1, -1};
const std::vector<int> dx = {0, 1, 0, -1, 1, -1, 1, -1};

}  // namespace ebi

#line 2 "data_structure/segtree.hpp"

#line 5 "data_structure/segtree.hpp"

namespace ebi {

template <class S, S (*op)(S, S), S (*e)()> struct segtree {
  private:
    int n;
    int sz;
    std::vector<S> data;

    void update(int i) {
        data[i] = op(data[2 * i], data[2 * i + 1]);
    }

  public:
    segtree(int n) : segtree(std::vector<S>(n, e())) {}
    segtree(const std::vector<S> &v) : n((int)v.size()), sz(1) {
        while (sz < n) sz *= 2;
        data = std::vector<S>(2 * sz, e());
        for (int i = 0; i < n; i++) {
            data[sz + i] = v[i];
        }
        for (int i = sz - 1; i >= 1; i--) update(i);
    }

    void set(int p, S x) {
        assert(0 <= p && p < n);
        p += sz;
        data[p] = x;
        while (p > 1) {
            p >>= 1;
            update(p);
        }
    }

    S get(int p) const {
        assert(0 <= p && p < n);
        return data[p + sz];
    }

    S prod(int l, int r) const {
        assert(0 <= l && l <= r && r <= n);
        S sml = e(), smr = e();
        l += sz;
        r += sz;
        while (l < r) {
            if (l & 1) sml = op(sml, data[l++]);
            if (r & 1) smr = op(data[--r], smr);
            l >>= 1;
            r >>= 1;
        }
        return op(sml, smr);
    }

    S all_prod() const {
        return data[1];
    }

    template <class F> int max_right(int l, F f) const {
        assert(0 <= l && l < n);
        assert(f(e()));
        if (l == n) return n;
        l += sz;
        S sm = e();
        do {
            while (l % 2 == 0) l >>= 1;
            if (!f(op(sm, data[l]))) {
                while (l < sz) {
                    l = 2 * l;
                    if (f(op(sm, data[l]))) {
                        sm = op(sm, data[l]);
                        l++;
                    }
                }
                return l - sz;
            }
            sm = op(sm, data[l]);
            l++;
        } while ((l & -l) != l);
        return n;
    }

    template <class F> int min_left(int r, F f) const {
        assert(0 <= r && r <= n);
        assert(f(e()));
        if (r == 0) return 0;
        r += sz;
        S sm = e();
        do {
            r--;
            while (r > 1 && (r % 2)) r >>= 1;
            if (!f(op(data[r], sm))) {
                while (r < sz) {
                    r = 2 * r + 1;
                    if (f(op(data[r], sm))) {
                        sm = op(data[r], sm);
                        r--;
                    }
                }
                return r + 1 - sz;
            }
            sm = op(data[r], sm);
        } while ((r & -r) != r);
        return 0;
    }

    S operator[](int p) const {
        return data[sz + p];
    }
};

}  // namespace ebi
#line 166 "a.cpp"

namespace ebi {

template <class S, S (*op)(S, S), S (*e)(), class data_structure>
struct segtree_2d {
  private:
  public:
    segtree_2d(int h, int w) : h(h), w(w), sz(1) {
        while (sz < h) sz <<= 1;
        data = std::vector<data_structure>(2 * sz, data_structure(w));
    }

    void set(int i, int j, S x) {
        i += sz;
        data[i].set(j, x);
        while (i > 1) {
            i >>= 1;
            S val = op(data[2 * i].get(j), data[2 * i + 1].get(j));
            data[i].set(j, val);
        }
    }

    S get(int i, int j) const {
        assert(0 <= i && i < h && 0 <= j && j < w);
        return data[i + sz].get(j);
    }

    S prod(int l, int r, int d, int u) const {
        assert(0 <= l && l <= r && r <= h);
        assert(0 <= d && d <= u && u <= w);
        l += sz;
        r += sz;
        S res = e();
        while (l < r) {
            if (l & 1) res = op(res, data[l++].prod(d, u));
            if (r & 1) res = op(data[--r].prod(d, u), res);
            l >>= 1;
            r >>= 1;
        }
        return res;
    }

  private:
    int h, w;
    int sz;
    std::vector<data_structure> data;
};

}  // namespace ebi

namespace ebi {

int op(int a, int b) {
    return a < b ? a : b;
}

int e() {
    return std::numeric_limits<int>::max();
}

void main_() {
    int r, c, q;
    while (std::cin >> r >> c >> q, !(r == 0 && c == 0 && q == 0)) {
        if (c == 1) {
            segtree<int, op, e> seg(r);
            rep(i, 0, r) {
                int grid;
                std::cin >> grid;
                seg.set(i, grid);
            }
            while (q--) {
                int l, d, r, u;
                std::cin >> l >> d >> r >> u;
                r++;
                u++;
                int ans = e();
                if(d < u) {
                    ans = seg.prod(l, r);
                }
                std::cout << ans << '\n';
            }
            continue;
        }
        segtree_2d<int, op, e, segtree<int, op, e>> seg2d(r, c);
        rep(i, 0, r) {
            rep(j, 0, c) {
                int grid;
                std::cin >> grid;
                seg2d.set(i, j, grid);
            }
        }
        while (q--) {
            int l, d, r, u;
            std::cin >> l >> d >> r >> u;
            r++;
            u++;
            std::cout << seg2d.prod(l, r, d, u) << '\n';
        }
    }
}

}  // namespace ebi

int main() {
    std::cout << std::fixed << std::setprecision(15);
    std::cin.tie(nullptr);
    std::ios::sync_with_stdio(false);
    int t = 1;
    // std::cin >> t;
    while (t--) {
        ebi::main_();
    }
    return 0;
}
accuracy: 1
time_ms: 220
memory_kb: 48136
final_rank: 1