首页 > 代码库 > ZOJ 2859 二维RMQ(模板)

ZOJ 2859 二维RMQ(模板)

这题求范围最小值,RMQ正好是用来解决这方面的,所以再适合不过了,又是离线静态输入输出的,所以时间比二维线段树快。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<bitset>
#define mem(a,b) memset(a,b,sizeof(a))
#define lson i<<1,l,mid
#define rson i<<1|1,mid+1,r
#define INF 510010
#define maxn 310
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int N;
int val[301][301];
int dp[maxn][maxn][9][9];
void RMQ_2D()
{
    for(int row = 1; row <= N; row++)
        for(int col = 1; col<=N; col++)
            dp[row][col][0][0] = val[row][col];
    int m = log(double(N)) / log(2.0);
    for(int i=0; i<=m; i++)
        for(int j=0; j<=m; j++)
        {
            if(i == 0 && j==0) continue;
            for(int row = 1; row+(1<<i)-1 <= N; row++)
                for(int col = 1; col+(1<<j)-1 <= N; col++)
                {
                    if(i == 0) dp[row][col][i][j] = min(dp[row][col][i][j-1] , dp[row][col+(1<<(j-1))][i][j-1]);  //水平划分
                    else dp[row][col][i][j] = min(dp[row][col][i-1][j] , dp[row+(1<<(i-1))][col][i-1][j]);    //竖直划分
                }
        }
}
int RMQ_2D(int x1,int x2,int y1,int y2)
{
    int kx = log(double(x2 - x1 +1)) / log(2.0);
    int ky = log(double(y2 - y1 +1)) / log(2.0);
    int m1 = dp[x1][y1][kx][ky];
    int m2 = dp[x2-(1<<kx)+1][y1][kx][ky];
    int m3 = dp[x1][y2-(1<<ky)+1][kx][ky];
    int m4 = dp[x2-(1<<kx)+1][y2-(1<<ky)+1][kx][ky];
    return min( min(m1,m2), min(m3,m4) );
}
int main()
{
    int T;
    scanf("%d",&T);
    int M;
    int x1,y1,x2,y2;
    while(T--)
    {
        scanf("%d",&N);
        for(int i=1; i<=N; i++)
            for(int j=1; j<=N; j++)
                scanf("%d",&val[i][j]);
        RMQ_2D();
        scanf("%d",&M);
        while(M--)
        {
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            printf("%d\n",RMQ_2D(x1,x2,y1,y2));
        }
    }
    return 0;
}