二维的相当于先求出每一行i的每一列j开始到j+2^j-1最值,然后求各个行和列之间的最值
#include <iostream>
#include <cstdio>
#include <cmath>
#include <memory.h>
using namespace std;
#define mmin(a,b) (a)<(b)?(a):(b);
const int maxn=310;
int dp[maxn][maxn][9][9],grid[maxn][maxn],n,q;
void init(){
for(int i=0;i<n;++i){
for (int j=0;j<n;++j){
dp[i][j][0][0]=grid[i][j];
}
}
int k=log(n*1.0)/log(2.0);
for(int i=0;i<=k;++i){//行
for (int j=0;j<=k;++j){//列
if(i==0&&j==0)continue;
for (int ii=0;ii+(1<<i)-1<n;++ii){//
for (int jj=0;jj+(1<<j)-1<n;++jj){
if(i==0){//初始i等于0的时候相当于把每一行的一维的最值算出来
dp[ii][jj][i][j]=mmin(dp[ii][jj][i][j-1],dp[ii][jj+(1<<(j-1))][i][j-1]);
}else{//因为每一行的各个列开始的最值已经全部求出来,现在相当于计算各行各列之间的最值
dp[ii][jj][i][j]=mmin(dp[ii][jj][i-1][j],dp[ii+(1<<(i-1))][jj][i-1][j]);
}
}
}
}
}
}
int query(int x1,int x2,int y1,int y2){
int k_x=log(x2-x1+1.0)/log(2.0);
int k_y=log(y2-y1+1.0)/log(2.0);
//下面的操作相当于把这个二维区间分割成了4个部分重叠的方块,然后求这4个方块的最值
int v1=mmin(dp[x1][y1][k_x][k_y],dp[x2-(1<<k_x)+1][y1][k_x][k_y]);
int v2=mmin(dp[x1][y2-(1<<k_y)+1][k_x][k_y],dp[x2-(1<<k_x)+1][y2-(1<<k_y)+1][k_x][k_y]);
return mmin(v1,v2);
}
int main(){
int t;
scanf("%d",&t);
while (t--){
scanf("%d",&n);
for (int i=0;i<n;++i){
for (int j=0;j<n;++j){
scanf("%d",&grid[i][j]);
}
}
init();
scanf("%d",&q);
while (q--){
int x1,x2,y1,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
printf("%d\n",query(x1-1,x2-1,y1-1,y2-1));
}
}
return 0;
}