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轴上的信息。这样就便于理解了。
*/