题目:
爱丽丝正在寻找最平坦的土地种植玉米。她花了很大的代价调查她的N×N公顷的方形农场(1≤N≤250)。每公顷有一个整数高度(0≤高度≤250)。有k(1≤K≤100000)组查询,整数B(1≤B≤N)是方形田地的一个边长,查询B×B子矩阵中最大高度和最小高度的差值。
输入:
第一行包含3个整数N、B和K。第2…N+1行,每行都包含N个整数,代表N×N公顷每公顷的高度,每行的第1个整数表示第一列,第2个整数都表示第二列。接下来K行,每行都包含两个整数(在1…N-B+1范围内),分别表示查询子矩阵左上角的行和列。
输出:
对每个查询,都单行输出子矩阵中最大高度和最小高度的差值。
输入样例:
5 3 1
5 1 2 6 3
1 3 5 2 7
7 2 4 6 1
9 9 8 6 5
0 6 9 3 9
1 2
输出样例:
5
题解:
本题属于二维区间最值查询问题,可以使用ST解决,只不过增加了一维,且查询时注意区间问题。
Fmax[k][i][j]表示第k行[i,i+2j -1]区间最大值,区间长度为2j 。
算法设计:
求出数据范围内所有log值,存在lb[ ]中。
将每个元素a[ ][ ] 都存入F[k][i][0]中。
创建二维ST。
从当前位置(x,y)开始,向右B列,向下B行,查询每一行的最大值和最小值,再求最大值好最小值。输出二维区间的最大值和最小值之差。
#include<bits/stdc++.h>
using namespace std;
#define maxn 250+1
int a[maxn][maxn];
int lb[maxn];
int Fmax[maxn][maxn][10];
int Fmin[maxn][maxn][10];
void Initlog()
{
lb[0]=-1;
for(int i=1;i<=maxn;i++)
lb[i]=(i&(i-1))?lb[i-1]:lb[i-1]+1;
}
void ST(int n)
{
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
Fmax[k][i][0]=Fmin[k][i][0]=a[k][i];
for(int k=1;k<=n;k++)
for(int j=1;j<=lb[n];j++)
for(int i=1;i<=n-(1<<j)+1;i++){
Fmax[k][i][j]=max(Fmax[k][i][j-1],Fmax[k][i+(1<<(j-1))][j-1]);
Fmin[k][i][j]=min(Fmin[k][i][j-1],Fmin[k][i+(1<<(j-1))][j-1]);
}
}
void solve(int x,int y,int B)
{
int k=lb[B];
int maxx=-1;
int minx=0x3f3f3f3f;
int l=y,r=y+B-1;
for(int i=x;i<x+B;i++)//查询每一行的最值
{
maxx=max(Fmax[i][l][k],Fmax[i][r-(1<<k)+1][k]);
minx=min(Fmin[i][l][l],Fmin[i][r-(1<<k)+1][k]);
}
printf("%d\n",maxx-minx);
}
int main()
{
int n,b,k;
int x,y;
cin>>n>>b>>k;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&a[i][j]);
Initlog();
ST(n);
for(int j=1;j<=k;j++)
{
scanf("%d%d",&x,&y);
solve(x,y,b);
}
}
/*
5 3 1
5 1 2 6 3
1 3 5 2 7
7 2 4 6 1
9 9 8 6 5
0 6 9 3 9
1 2
*/