题目地址:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2859
题目意思:
给你一个矩阵,求出子矩阵中的最小元素
解题思路:
之前用二维的线段树做过,但是查询时间是O(logn*logn)
现在用二维RMQ的话,可以把查询时间做到O(1)
它的预处理时间是O(n*n*logn*logn)
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn = 310;
int map[maxn][maxn];
int dp[maxn][maxn][9][9];
int n;
void init_rmq()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
dp[i][j][0][0]=map[i][j];
}
}
for(int i=0;(1<<i)<=n;i++)
{
for(int j=0;(1<<j)<=n;j++)
{
if(i==0 && j==0)
continue;
for(int row=1;row+(1<<i)-1<=n;row++)
{
for(int col=1;col+(1<<j)-1<=n;col++)
{
if(i==0)
{
dp[row][col][i][j] =
min(dp[row][col][i][j-1],dp[row][col+(1<<(j-1))][i][j-1]);
}
else
{
dp[row][col][i][j] =
min(dp[row][col][i-1][j],dp[row+(1<<(i-1))][col][i-1][j]);
}
}
}
}
}
}
int query(int x1,int y1,int x2,int y2)
{
int kx=log(double(x2-x1+1))/log(2.0);
int ky=log(double(y2-y1+1))/log(2.0);
int m1=dp[x1][y1][kx][ky];
int m2 = dp[x2-(1<<kx)+1][y1][kx][ky];
int m3 = dp[x1][y2-(1<<ky)+1][kx][ky];
int m4 = dp[x2-(1<<kx)+1][y2-(1<<ky)+1][kx][ky];
return min( min(m1,m2), min(m3,m4) );
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&map[i][j]);
int m;
scanf("%d",&m);
init_rmq();
while(m--)
{
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
int ans=query(x1,y1,x2,y2);
printf("%d\n",ans);
}
}
return 0;
}