Problem Description
Paul draw a big m*n matrix A last month, whose entries Ai,j are all integer numbers ( 1 <= i <= m, 1 <= j <= n ). Now he selects some sub-matrices, hoping to find the maximum number. Then he finds that there may be more than one maximum number, he also wants to know the number of them. But soon he find that it is too complex, so he changes his mind, he just want to know whether there is a maximum at the four corners of the sub-matrix, he calls this “Check corners”. It’s a boring job when selecting too many sub-matrices, so he asks you for help. (For the “Check corners” part: If the sub-matrix has only one row or column just check the two endpoints. If the sub-matrix has only one entry just output “yes”.)
【题目分析】
第一个结果是比较难的。但是第二个答案是比较简单的,我们可以比较一下最大值和四个角上的值就可以了。
很明显,第一个问题是一个二维的RMQ问题。解法有很多种,比如树套树(线段树&树状数组)甚至平衡树也可以解这道题。
我选择了二维的ST算法。即使十分占空间,但是时间还是比较快的。数组再开大一点点就会MLE.
【代码】
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
inline int max(int a,int b)
{return a>b?a:b;}
int n,m,v[302][302],mx[302][302][9][9];
inline void init()
{
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j)
mx[i][j][0][0]=v[i][j];
int k1=(int)(log(double(n))/log(2.0));
int k2=(int)(log(double(m))/log(2.0));
for (int i=0;i<=k1;++i)
for (int j=0;j<=k2;++j)
if (i!=0||j!=0)
{
for (int r=1;r+(1<<i)-1<=n;++r)
for (int c=1;c+(1<<j)-1<=m;++c)
{
if (i==0) mx[r][c][i][j]=max(mx[r][c][i][j-1],mx[r][c+(1<<(j-1))][i][j-1]);
else mx[r][c][i][j]=max(mx[r][c][i-1][j],mx[r+(1<<(i-1))][c][i-1][j]);
}
}
}
inline int query(int r1,int c1,int r2,int c2)
{
int kr=(int)(log(double(r2-r1+1))/log(2.0));
int kc=(int)(log(double(c2-c1+1))/log(2.0));
int t1=mx[r1][c1][kr][kc];
int t2=mx[r2-(1<<kr)+1][c1][kr][kc];
int t3=mx[r1][c2-(1<<kc)+1][kr][kc];
int t4=mx[r2-(1<<kr)+1][c2-(1<<kc)+1][kr][kc];
return max(max(t1,t2),max(t3,t4));
}
int main()
{
while (~scanf("%d%d",&n,&m))
{
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j)
scanf("%d",&v[i][j]);
init();
int q;
scanf("%d",&q);
while (q--)
{
int r1,c1,r2,c2;
scanf("%d%d%d%d",&r1,&c1,&r2,&c2);
int ans=query(r1,c1,r2,c2);
printf("%d ",ans);
if (v[r1][c1]==ans||v[r1][c2]==ans||v[r2][c1]==ans||v[r2][c2]==ans)
printf("yes\n");
else printf("no\n");
}
}
}