把整个矩阵按sqrt(n)为一块,分成n/sqrt(n)块,在查询的时候就按照小块进行分割。边缘部分按照顺时针分成相同的小条。
代码如下:
/*The solution of RMQ using a <O(n), O(sqrt(n))> algrithom *http://www.topcoder.com/tc?module=Static&d1=tutorials&d2=lowestCommonAncestor */ #include <stdio.h> #define min(a,b) (((a)<(b))?(a):(b)) #define N 310 int matrix[N][N]; int M[17][17]; int mysqrt(int n) { int pos = 0, i = 0; while(i <= n) { if( (pos+1)*(pos+1) == i) pos += 1; i++; } return pos; } int minMatrix(int choose, int i, int j, int u, int v) { int k, t; int min; int flag = 0; switch(choose) { case 1: min = matrix[i][j]; for(k = i; k <= u; k++) for(t = j; t <= v; t++) { flag = 1; if(matrix[k][t] < min) min = matrix[k][t]; } break; case 2: min = M[i][j]; for(k = i; k <= u; k++) for(t = j; t <= v; t++) { flag = 1; if(M[k][t] < min) min = M[k][t]; } break; } return flag?min:0x7FFFFFFF; } void initCUT(int n) { int sn = mysqrt(n); int block = n/sn; int i, j; for(i = 0; i < block; i++) for(j = 0; j < block; j++) { M[i][j] = minMatrix(1, sn*i, sn*j, sn*(i+1)-1, sn*(j+1)-1); } } int askCUT(int n, int r1, int c1, int r2, int c2) { int sn = mysqrt(n); if(r2-r1+1<2*sn || c2-c1+1<2*sn) { return minMatrix(1, r1, c1, r2, c2); } /*subtitle in M[][]*/ int a = (r1%sn == 0)?(r1/sn):(r1/sn+1), b = (c1%sn == 0)?(c1/sn):(c1/sn+1), c = ((r2+1)%sn == 0)?(r2/sn):(r2/sn-1), d = ((c2+1)%sn == 0)?(c2/sn):(c2/sn-1); /*subtitle in matrix[][]*/ int lt = a*sn,/*left top*/ rt = b*sn,/*right top*/ ld = (c+1)*sn - 1,/*left down*/ rd = (d+1)*sn - 1;/*rignt down*/ int min1 = minMatrix(2, a, b, c, d); int min2 = minMatrix(1, r1, c1, lt-1, rd); int min3 = minMatrix(1, r1, rd+1, ld, c2); int min4 = minMatrix(1, ld+1, rt, r2, c2); int min5 = minMatrix(1, lt, c1, r2, rt-1); int min6 = min(min(min2, min3), min(min4, min5)); return min(min1, min6); } int main() { int t; scanf("%d", &t); while(t--) { int n; scanf("%d", &n); int i, j; for(i = 0; i < n; i++) for(j = 0; j < n; j++) scanf("%d", &(matrix[i][j])); if(n > 3) initCUT(n); int queries; scanf("%d", &queries); while(queries--) { int r1, c1, r2, c2; scanf("%d%d%d%d", &r1, &c1, &r2, &c2); if(n > 3) printf("%d\n", askCUT(n, r1-1, c1-1, r2-1, c2-1)); else printf("%d\n", minMatrix(1, r1-1, c1-1, r2-1, c2-1)); } } return 0; }
参考算法:http://www.topcoder.com/tc?module=Static&d1=tutorials&d2=lowestCommonAncestor