4 4 4 4 10 7 2 13 9 11 5 7 8 20 13 20 8 2 4 1 1 4 4 1 1 3 3 1 3 3 4 1 1 1 1
20 no 13 no 20 yes4 yes
题意:n,m是矩阵的长宽,然后给出一个矩阵。 q次询问,每次给出矩阵的左上角坐标和右下角坐标,求在这个小矩阵里的最大值,还有这个最大值是否是矩阵四个角其中之一。
思路:普通的RMQ用来求一个区间的最大值,这里是平面问题,于是想到用二维RMQ来求四边形的最大值。写法和一维差不多,细节多注意下就好。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; #define N 305 int ma[N][N]; int dp[N][N][9][9]; int maxs(int a,int b,int c,int d) { int maxn=a; if(b>maxn) maxn=b; if(c>maxn) maxn=c; if(d>maxn) maxn=d; return maxn; } void makermq(int m,int n) { for(int i=0; i<m; i++) for(int j=0; j<n; j++) dp[i][j][0][0]=ma[i][j]; for(int q=0; (1<<q)<=m; q++) { for(int w=0; (1<<w)<=n; w++) { if(q==0&&w==0) continue; for(int j=0; j+(1<<q)-1<m; j++) { for(int i=0; i+(1<<w)-1<n; i++) { if(q==0) dp[j][i][q][w]=max(dp[j][i][q][w-1],dp[j][i+(1<<(w-1))][q][w-1]); else if(w==0) dp[j][i][q][w]=max(dp[j][i][q-1][w],dp[j+(1<<(q-1))][i][q-1][w]); else dp[j][i][q][w]=maxs(dp[j][i][q-1][w],dp[j+(1<<(q-1))][i][q-1][w], dp[j][i][q][w-1],dp[j][i+(1<<(w-1))][q][w-1]); } } } } } int finds(int x1,int y1,int x2,int y2) { int k1=(int)(log(x2-x1+1.0)/log(2.0)); int k2=(int)(log(y2-y1+1.0)/log(2.0)); return maxs(dp[x1][y1][k1][k2],dp[x2-(1<<k1)+1][y2-(1<<k2)+1][k1][k2], dp[x1][y2-(1<<k2)+1][k1][k2],dp[x2-(1<<k1)+1][y1][k1][k2]); } int main() { int n,m,q; int x1,y1,x2,y2; while(scanf("%d %d",&m,&n)!=EOF) { for(int i=0; i<m; i++) for(int j=0; j<n; j++) scanf("%d",&ma[i][j]); makermq(m,n); scanf("%d",&q); while(q--) { scanf("%d %d %d %d",&x1,&y1,&x2,&y2); x1--; y1--; x2--; y2--; int ans=finds(x1,y1,x2,y2); printf("%d ",ans); if(ans==ma[x1][y1]||ans==ma[x1][y2]||ans==ma[x2][y1]||ans==ma[x2][y2]) printf("yes\n"); else printf("no\n"); } } return 0; }