ZOJ 2859 Matrix Searching 二维rmq

    二维的rmq 和一维的rmq 其实非常相似,我们定义 dp[r][c][i][j] 为 覆盖了 r行c列 到 r+2^i-1行 c+2^j-1列的 标记值(如最大最小)。

dp转移就很容易了:

  当i为0 ,j为0 的时候就是 数组[r][c]的值,  当i= 0 ,就j不为0的时候,就和一维的rmq一样,此时即对第一行求rmq;

   我们只看二维rmq的行,那么二维rmq 也变成了一维, 而且 因为求了第一行的dp相关值了,又可以按照一维的方式递推。


查询分成四块:

举个例 要查询:(3 3)( 8 9)这个子矩阵的最小值吧;因为8-3 = 5 >4  9-3=6>4

所以查询的结果为  :  (3,3,)(3+4,3+4)  和 (8,3)(8,7)和 (3,8)(7,9)和 (8,8)(8,9)四个子矩形的最小值

#include <stdio.h>   
#include <iostream>
#include <string.h>   
#include <cmath>
#include <vector>
#include <set>
#include <algorithm>   
using namespace std;

typedef pair<int,int> pii;
typedef long long ll; typedef double dl;
typedef vector<pii> vii;
typedef set<pii> sii;

#define sfint(x) scanf("%d",&x)
#define sfint2(x,y) scanf("%d%d",&x,&y)
#define sfint3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define sfstr(c) scanf("%s",c)
#define pfint(x) printf("%d\n",x)
#define fr(i,s,n) for(i=s;i<n;++i)
#define _fr(i,n,s) for(i=n-1;i>=s;--i)
#define cl(a) memset(a,0,sizeof(a))

#define _has(s,x) ((s&(_ni(x)))!=0)
#define _hasL(s,x) ((s&(_niL(x)))!=0LL)
template<class T> inline T _lowbit(const int &x){ return (x^(x-1))&x; }  
template<class T> inline int _bitsize(const T &x){ return (x==0)?0:(1+_bitsize(x&(x-1))); }

const dl _pi=acos(-1.0);
const dl _eps=1e-6;
const int N = 301;
int t,n;
int dp[N][N][9][9];
void in(int &a)
{
	char c,f;
	while(((f=getchar())<'0'||f>'9')&&f!='-');
	c=(f=='-')?getchar():f;
	for(a=0;c>='0'&&c<='9';c=getchar())a=a*10+c-'0';
	if(f=='-')a=-a;
}
void initrmq(){
	int i,j;
	int m = log(double(n)) / log(2.0);
	fr(i,0,m+1){
		fr(j,0,m+1){
			if (i==0 && j==0) continue;
			for(int r = 0; r+(1<<i)-1 < n; ++r){
				for(int c = 0; c+(1<<j)-1 < n; ++c){
					if(i == 0) dp[r][c][i][j] = min(dp[r][c][i][j-1] , dp[r][c+(1<<(j-1))][i][j-1]); 
					else dp[r][c][i][j] = min(dp[r][c][i-1][j] , dp[r+(1<<(i-1))][c][i-1][j]);
				}
			}
		}
	}
}
int rmq_2d_query(int X1,int Y1,int X2,int Y2){
	int x = log(double(X2 - X1 +1)) / log(2.0); 
	int y = log(double(Y2 - Y1 +1)) / log(2.0); 
	int m1 = dp[X1][Y1][x][y];
	int m2 = dp[X2-(1<<x)+1][Y1][x][y];
	int m3 = dp[X1][Y2-(1<<y)+1][x][y];
	int m4 = dp[X2-(1<<x)+1][Y2-(1<<y)+1][x][y];
	return min(min(m1,m2),min(m3,m4));
}

void inp(){
	int i,j,m,X1,Y1,X2,Y2;
	in(n);
	fr(i , 0,n){
		fr(j,0,n){
			in(dp[i][j][0][0]);
		}
	}
	initrmq();
	sfint(m);
	while(m--){
		in(X1);in(Y1);in(X2);in(Y2);
		printf("%d\n",rmq_2d_query(X1-1,Y1-1,X2-1,Y2-1));
	}
}
int main(){
	sfint(t);
	while(t--){
		inp();
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值