POJ - 2019 Cornfields(二维rmq)

题目链接:点击这里

题目大意:
给定一个 n × n ( n ≤ 250 ) n\times n(n\le 250) n×n(n250) 的方阵,以及 k ( k ≤ 1 0 5 ) k(k\le 10^5) k(k105) 个询问。
每次询问以 ( x i , y i ) (x_i,y_i) (xi,yi) 为左上角,边长为 b b b 的子方阵中,最大值和最小值的差

题目分析:
考虑使用二维 st \text{st} st 表解决此问题
d p [ i ] [ j ] [ k ] [ o ] dp[i][j][k][o] dp[i][j][k][o] 表示以 ( i , j ) (i,j) (i,j) 为左下角的点,横纵坐标跨度分别为 2 k , 2 o 2^k,2^o 2k,2o 这个矩形范围内的最值(下以最大值为例)
我们分四种情况来转移这个 d p dp dp
1. k = 0 , o = 0 k=0,o=0 k=0,o=0 (一个点):
d p [ i ] [ j ] [ k ] [ o ] = a [ i ] [ j ] dp[i][j][k][o]=a[i][j] dp[i][j][k][o]=a[i][j]
2. k = 0 , o ≠ 0 k=0,o\not=0 k=0,o=0 (一列):
d p [ i ] [ j ] [ k ] [ o ] = m a x ( d p [ i ] [ j ] [ k ] [ o − 1 ] , d p [ i ] [ j + 2 o − 1 ] [ k ] [ o − 1 ] ) dp[i][j][k][o]=max(dp[i][j][k][o-1],dp[i][j+2^{o-1}][k][o-1]) dp[i][j][k][o]=max(dp[i][j][k][o1],dp[i][j+2o1][k][o1])
3. k ≠ 0 , o = 0 k\not=0,o=0 k=0,o=0 (一行):
d p [ i ] [ j ] [ k ] [ o ] = m a x ( d p [ i ] [ j ] [ k − 1 ] [ o ] , d p [ i + 2 k − 1 ] [ j ] [ k − 1 ] [ o ] ) dp[i][j][k][o]=max(dp[i][j][k-1][o],dp[i+2^{k-1}][j][k-1][o]) dp[i][j][k][o]=max(dp[i][j][k1][o],dp[i+2k1][j][k1][o])
4. k ≠ 0 , o ≠ 0 k\not=0,o\not=0 k=0,o=0 (一个矩形):
d p [ i ] [ j ] [ k ] [ o ] = m a x ( d p [ i ] [ j ] [ k − 1 ] [ o − 1 ] , d p [ i ] [ j + 2 o − 1 ] [ k ] [ o − 1 ] , d p [ i + 2 k − 1 ] [ j ] [ k − 1 ] [ o ] , d p [ i + 2 k − 1 ] [ j 2 k − 1 ] [ k − 1 ] [ o − 1 ] ) dp[i][j][k][o]=max(dp[i][j][k-1][o-1],dp[i][j+2^{o-1}][k][o-1],dp[i+2^{k-1}][j][k-1][o],dp[i+2^{k-1}][j2^{k-1}][k-1][o-1]) dp[i][j][k][o]=max(dp[i][j][k1][o1],dp[i][j+2o1][k][o1],dp[i+2k1][j][k1][o],dp[i+2k1][j2k1][k1][o1])
对于查询操作,我们可以把目标矩形化成 4 4 4 部分矩形(可能有交集),他们的最值就是查询答案

具体细节见代码:

// Problem: Cornfields
// Contest: Virtual Judge - POJ
// URL: https://vjudge.net/problem/POJ-2019#author=pearfish16
// Memory Limit: 30 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

//#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast","inline","-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<unordered_map>
#define ll long long
#define inf 0x3f3f3f3f
#define Inf 0x3f3f3f3f3f3f3f3f
//#define int  ll
#define endl '\n'
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
using namespace std;
int read()
{
	int res = 0,flag = 1;
	char ch = getchar();
	while(ch<'0' || ch>'9')
	{
		if(ch == '-') flag = -1;
		ch = getchar();
	}
	while(ch>='0' && ch<='9')
	{
		res = (res<<3)+(res<<1)+(ch^48);//res*10+ch-'0';
		ch = getchar();
	}
	return res*flag;
}
const int maxn = 250+5;
const int mod = 1e9+7;
const double pi = acos(-1);
const double eps = 1e-8;
int n,b,k,a[maxn][maxn],maxx[maxn][maxn][10][10],minn[maxn][maxn][10][10];
void init(int n,int m)
{
	for(int k = 0;(1<<k) <= n;k++)
	for(int o = 0;(1<<o) <= m;o++)
		for(int i = 1;i+(1<<k)-1 <= n;i++)
		for(int j = 1;j+(1<<o)-1 <= m;j++)
		{
			if(!k && !o) maxx[i][j][k][o] = minn[i][j][k][o] = a[i][j];
			if(!k && o) 
			{
				maxx[i][j][k][o] = max(maxx[i][j][k][o-1],maxx[i][j+(1<<(o-1))][k][o-1]);
				minn[i][j][k][o] = min(minn[i][j][k][o-1],minn[i][j+(1<<(o-1))][k][o-1]);
			}
			if(k && !o)
			{
				maxx[i][j][k][o] = max(maxx[i][j][k-1][o],maxx[i+(1<<(k-1))][j][k-1][o]);
				minn[i][j][k][o] = min(minn[i][j][k-1][o],minn[i+(1<<(k-1))][j][k-1][0]);
			}
			if(k && o)
			{
				maxx[i][j][k][o] = max({maxx[i][j][k-1][o-1],maxx[i][j+(1<<(o-1))][k-1][o-1],maxx[i+(1<<(k-1))][j][k-1][o-1],maxx[i+(1<<(k-1))][j+(1<<(o-1))][k-1][o-1]});
				minn[i][j][k][o] = min({minn[i][j][k-1][o-1],minn[i][j+(1<<(o-1))][k-1][o-1],minn[i+(1<<(k-1))][j][k-1][o-1],minn[i+(1<<(k-1))][j+(1<<(o-1))][k-1][o-1]});
			}
		}
}
int get_max(int x,int y,int xx,int yy)
{
	int k = log2(xx-x+1),o = log2(yy-y+1);
	xx = xx-(1<<k)+1; yy = yy-(1<<o)+1;
	return max({maxx[x][y][k][o],maxx[xx][y][k][o],maxx[x][yy][k][o],maxx[xx][yy][k][o]});
}
int get_min(int x,int y,int xx,int yy)
{
	int k = log2(xx-x+1),o = log2(yy-y+1);
	xx = xx-(1<<k)+1; yy = yy-(1<<o)+1;
	return min({minn[x][y][k][o],minn[xx][y][k][o],minn[x][yy][k][o],minn[xx][yy][k][o]});
}
int main()
{
	n = read(),b = read(),k = read();
	for(int i = 1;i <= n;i++)
		for(int j = 1;j <= n;j++) a[i][j] = read();
	init(n,n);
	while(k--)
	{
		int x = read(),y = read();
		printf("%d\n",get_max(x,y,x+b-1,y+b-1)-get_min(x,y,x+b-1,y+b-1));
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值