二维RMQ(Range Minimum Query)

来源:互联网 发布:网络女神雅典娜 编辑:程序博客网 时间:2024/05/29 04:47

二维RMQ(Range Minimum Query)

先来看一维情形:
给定一个数组x以及大量的查询,查询内容是任意区间内的最小值,例如数组长度为n,则查询为从x[a]到x[b]中的最小值,0<=a<b<n, a, b 任意。
问题是如何进行预处理,使得每次查询时间为O(1)。

解法:计算出所有长度为2^i的区间的最小值,则任[a,b]区间可以拆为两个长度为2^i的区间的并集,i=log(b-a)。
例如查询1到100间的最小值,[1,64],[37,100]的最小值已知,则[1,100]的最小值,为这两者中的小者。
算法的空间和时间复杂度均为O(logN)

由此可以推演到二维情况,给一个n*n的矩阵,要查询任意子矩阵的最小值。
解法类似,计算出所有大小为2^i*2^j的子矩阵,然后查询时候,每个子矩阵可以看成是四个预处理矩阵的并集,查询时间仍然为O(1),而预处理的复杂度为O(N*N*logN*lonN)

典型的题目如zoj的2859题,


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.

代码:
#include<iostream>
#include<cstdio>

using namespace std;

int mat[310][310];
int table[9][9][310][310];
int n;
int b[] = {
 1, 2, 4, 8, 16, 32, 64, 128, 256, 512
};

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

int mylog(int n)
{
 if (n == 0)
  return 0;

 int i = 0;
 while (true) {
  if (n < b[i])
   return i - 1;
  ++i;
 }
 return -1;
}

void rmq()
{
 // 从小到大计算,保证后来用到的都已经计算过
 for(int i=0;i<=mylog(n);++i) // width
  for(int j=0;j<=mylog(n);++j){ //height
   if(i==0 && j==0)
    continue;
   for(int ii=0;ii+b[j]<=n;++ii)
    for(int jj=0;jj+b[i]<=n;++jj){
     if(i==0)
      table[i][j][ii][jj]=minn(table[i][j-1][ii][jj],table[i][j-1][ii+b[j-1]][jj]);
     else
      table[i][j][ii][jj]=minn(table[i-1][j][ii][jj],table[i-1][j][ii][jj+b[i-1]]);
    }
  }
}

int main()
{

 int T;
 cin >> T;
 while (T--) {
  cin >> n;
  for (int i = 0; i < n; ++i)
   for (int j = 0; j < n; ++j) {
    cin >> mat[i][j];
    table[0][0][i][j] = mat[i][j];
   }

   rmq();
   long N;
   cin >> N;
   int r1, c1, r2, c2;
   for (int i = 0; i < N; ++i) {
    scanf("%d%d%d%d",&r1,&c1,&r2,&c2);
    --r1;
    --c1;
    --r2;
    --c2;
    int w=mylog(c2-c1+1);
    int h=mylog(r2-r1+1);
    printf("%d/n",minn(table[w][h][r1][c1],minn(table[w][h][r1][c2-b[w]+1],minn(table[w][h][r2-b[h]+1][c1],table[w][h][r2-b[h]+1][c2-b[w]+1]))));
   }
 }

 return 0;

原创粉丝点击