ZOJ-2859 Matrix Searching (二維線段樹)

Matrix Searching

Time Limit: 10 Seconds      Memory Limit: 32768 KB

Given an n*n matrix A, whose entries Ai,j are integer numbers ( 1 <= i <= n, 1 <= j <= n ). An operation FIND the minimun number in a given ssub-matrix.

Input

The first line of the input contains a single integer T , the number of test cases.

For each test case, the first line contains one integer n (1 <= n <= 300), which is the sizes of the matrix, respectively. The next n lines with n integers each gives the elements of the matrix.

The next line contains a single integer N (1 <= N <= 1,000,000), the number of queries. The next N lines give one query on each line, with four integers r1, c1, r2, c2 (1 <= r1 <= r2 <= n, 1 <= c1 <= c2 <= n), which are the indices of the upper-left corner and lower-right corner of the sub-matrix in question.

Output

For each test case, print N lines with one number on each line, the required minimum integer in the sub-matrix.

Sample Input

1
2
2 -1
2 3
2
1 1 2 2
1 1 2 1

Sample Output

-1
2


#include <bits/stdc++.h>  
using namespace std;    
const int maxn = 333;  
const int INF = 1 << 30;  
struct tree{  
    int mi[maxn << 2];  
}c[maxn << 2];  
int minv, maxv, n, x;  
void buildy(int ox, int oy, int l, int r){   
    c[ox].mi[oy] = INF;  
    if(l == r) return;  
    int mid = l + r >> 1;  
    buildy(ox, oy << 1, l, mid);  
    buildy(ox, oy << 1 | 1, mid + 1, r);  
}  
void buildx(int o, int l, int r){  
    buildy(o, 1, 1, n);  
    if(l == r) return;  
    int mid = l + r >> 1;  
    buildx(o << 1, l, mid);  
    buildx(o << 1 | 1, mid + 1, r);  
}  
void addy(int ox, int oy, int l, int r, int id, int v){  
    if(l == r){  
        c[ox].mi[oy] = v; return;  
    }  
    int mid = l + r >> 1;  
    if(id <= mid) addy(ox, oy << 1, l, mid, id, v);  
    else addy(ox, oy << 1 | 1, mid + 1, r, id, v);  
    c[ox].mi[oy] = min(c[ox].mi[oy << 1], c[ox].mi[oy << 1 | 1]);  
}  
void pushupY(int ox, int oy, int l, int r, int id){   
    c[ox].mi[oy] = min(c[ox << 1].mi[oy], c[ox << 1 | 1].mi[oy]);  
    if(l == r) return;  
    int mid = l + r >> 1;  
    if(id <= mid) pushupY(ox, oy << 1, l, mid, id);  
    else pushupY(ox, oy << 1 | 1, mid + 1, r, id);  
}  
void addx(int o, int l, int r, int x, int y, int v){  
    if(l == r){  
        addy(o, 1, 1, n, y, v); return;  
    }  
    int mid = l + r >> 1;  
    if(x <= mid) addx(o << 1, l, mid, x, y, v);  
    else addx(o << 1 | 1, mid + 1, r, x, y, v);  
    pushupY(o, 1, 1, n, y);  
}  
void queryy(int ox, int oy, int l, int r, int L, int R){  
    if(l >= L && r <= R){  
        minv = min(minv, c[ox].mi[oy]);   
        return;  
    }  
    int mid = l + r >> 1;  
    if(mid >= L) queryy(ox, oy << 1, l, mid, L, R);  
    if(mid < R) queryy(ox, oy << 1 | 1, mid + 1, r, L, R);  
}  
void queryx(int o, int l, int r, int L, int R, int yl, int yr){  
    if(l >= L && r <= R){  
        queryy(o, 1, 1, n, yl, yr);  
        return;  
    }  
    int mid = l + r >> 1;  
    if(mid >= L) queryx(o << 1, l, mid, L, R, yl, yr);  
    if(mid < R) queryx(o << 1 | 1, mid + 1, r, L, R, yl, yr);  
}  
int main(){    
    int T;  
    scanf("%d", &T);  
    while(T--){  
        scanf("%d", &n);  
        buildx(1, 1, n);  
        for(int i = 1; i <= n; ++i){  
            for(int j = 1; j <= n; ++j){  
                scanf("%d", &x);  
                addx(1, 1, n, i, j, x);  
            }  
        }  
        int m, x1, x2, y1, y2;  
        scanf("%d", &m);  
        while(m--){  
            scanf("%d %d %d %d", &x1, &y1, &x2, &y2);  
            minv = INF; 
            queryx(1, 1, n, x1, x2, y1, y2);  
            printf("%d\n", minv);   
        }  
    }  
    return 0;  
}    
  
/* 
題意: 
300*300的矩陣,每次query一個子塊的最小值。 
 
思路: 
二位線段樹裸題。就是將x映射到一棵線段樹上,然後線段樹上的每個結點在維護一棵線段樹, 
用於維護y軸上的信息。這樣就便於理解了。 
*/  


發佈了165 篇原創文章 · 獲贊 4 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章