题目地址:点击打开链接
题意:
给你一个n*n的矩阵,给你一个点矩阵左上角(x, y),其大小为b*b,有q个询问,每次询问求该矩阵内的最大值和最小值的差。
思路:
这题因为数据和诺所以暴力也可以。
RMQ n^2logn预处理O(n)查询也可以:
1、一维RMQ可以用来求线性区间最大值问题。那么我们不如将一维变成二维,将maxn[][]变成maxn[i][j][k]表示在第i行中,以j为起点,长度为1<<k区间内的最值。
2、然后我们N^2LogN预处理这个问题。然后O(n)来查询区间最大值和最小的值的差即可。
还有个更好的二维RMQ模板,可以O(1)查询,推荐使用第二个模板
O(n)查询代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn = 250;
const int INF = 0x3f3f3f3f;
int dpMax[maxn][maxn][20], dpMin[maxn][maxn][20], a[maxn][maxn], n, b, q, Max, Min;
void initRMQ()
{
int len = (int)log2(n);
for(int row = 1; row <= n; row++)
for(int j = 1; j <= len; j++)
for(int i = 1; i+(1<<j)-1 <= n; i++)
{
dpMax[row][i][j] = max(dpMax[row][i][j-1], dpMax[row][i+(1<<(j-1))][j-1]);
dpMin[row][i][j] = min(dpMin[row][i][j-1], dpMin[row][i+(1<<(j-1))][j-1]);
}
}
void RMQ(int x, int y)
{
for(int i = x; i <= x+b-1; i++)
{
int k = (int)log2(b);
Max = max(Max, max(dpMax[i][y][k], dpMax[i][y+b-1-(1<<k)+1][k]));
Min = min(Min, min(dpMin[i][y][k], dpMin[i][y+b-1-(1<<k)+1][k]));
}
}
int main(void)
{
while(cin >> n >> b >> q)
{
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
scanf("%d", &a[i][j]), dpMax[i][j][0] = dpMin[i][j][0] = a[i][j];
initRMQ();
while(q--)
{
int x, y;
scanf("%d%d", &x, &y);
Max = -INF, Min = INF;
RMQ(x, y);
printf("%d\n", Max-Min);
}
}
return 0;
}
kuangbin的O(1)查询模板:
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
int val[255][255];
int mm[255]; //mm[x]存的是log2(x)的值
int dpmin[255][255][8][8];//最小值
int dpmax[255][255][8][8];//最大值
void initRMQ(int n,int m)
{
for(int i = 1;i <= n;i++)
for(int j = 1;j <= m;j++)
dpmin[i][j][0][0] = dpmax[i][j][0][0] = val[i][j];
for(int ii = 0; ii <= mm[n]; ii++)
for(int jj = 0; jj <= mm[m]; jj++)
if(ii+jj)
for(int i = 1; i + (1<<ii) - 1 <= n; i++)
for(int j = 1; j + (1<<jj) - 1 <= m; j++)
{
if(ii)
{
dpmin[i][j][ii][jj] = min(dpmin[i][j][ii-1][jj],dpmin[i+(1<<(ii-1))][j][ii-1][jj]);
dpmax[i][j][ii][jj] = max(dpmax[i][j][ii-1][jj],dpmax[i+(1<<(ii-1))][j][ii-1][jj]);
}
else
{
dpmin[i][j][ii][jj] = min(dpmin[i][j][ii][jj-1],dpmin[i][j+(1<<(jj-1))][ii][jj-1]);
dpmax[i][j][ii][jj] = max(dpmax[i][j][ii][jj-1],dpmax[i][j+(1<<(jj-1))][ii][jj-1]);
}
}
}
//查询矩形的最大值
int rmq1(int x1,int y1,int x2,int y2)
{
int k1 = mm[x2-x1+1];
int k2 = mm[y2-y1+1];
x2 = x2 - (1<<k1) + 1;
y2 = y2 - (1<<k2) + 1;
return max(max(dpmax[x1][y1][k1][k2],dpmax[x1][y2][k1][k2]),max(dpmax[x2][y1][k1][k2],dpmax[x2][y2][k1][k2]));
}
//查询矩形的最小值
int rmq2(int x1,int y1,int x2,int y2)
{
int k1 = mm[x2-x1+1];
int k2 = mm[y2-y1+1];
x2 = x2 - (1<<k1) + 1;
y2 = y2 - (1<<k2) + 1;
return min(min(dpmin[x1][y1][k1][k2],dpmin[x1][y2][k1][k2]),min(dpmin[x2][y1][k1][k2],dpmin[x2][y2][k1][k2]));
}
int main()
{
mm[0] = -1;
for(int i = 1;i < 255;i++)
mm[i] = ((i&(i-1))==0)?mm[i-1]+1:mm[i-1];
int N,B,K;
while(scanf("%d%d%d",&N,&B,&K)==3)
{
for(int i = 1;i <= N;i++)
for(int j = 1;j <= N;j++)
scanf("%d",&val[i][j]);
initRMQ(N,N);
int x,y;
while(K--)
{
scanf("%d%d",&x,&y);
printf("%d\n",rmq1(x,y,x+B-1,y+B-1)-rmq2(x,y,x+B-1,y+B-1));
}
}
return 0;
}