zoj 2859(二维RMQ)

14 篇文章 0 订阅
Matrix Searching

Time Limit: 10 Seconds       Memory Limit: 32768 KB

Given an n*n matrix A, whose entries Ai,j are integer numbers ( 1 <= i <= n, 1 <= j <= n ). An operation FIND the minimun number in a given ssub-matrix.

Input

The first line of the input contains a single integer T , the number of test cases.

For each test case, the first line contains one integer n (1 <= n <= 300), which is the sizes of the matrix, respectively. The next n lines with n integers each gives the elements of the matrix.

The next line contains a single integer N (1 <= N <= 1,000,000), the number of queries. The next N lines give one query on each line, with four integers r1, c1, r2, c2 (1 <= r1 <= r2 <= n, 1 <= c1 <= c2 <= n), which are the indices of the upper-left corner and lower-right corner of the sub-matrix in question.

Output

For each test case, print N lines with one number on each line, the required minimum integer in the sub-matrix.

Sample Input

1
2
2 -1
2 3
2
1 1 2 2
1 1 2 1

Sample Output

-1
2


Author:  PENG, Peng

Source: ZOJ Monthly, June 2007

题目:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2859

分析:这题很明显要求二维的最值,也就是二维RMQ问题,可以用很多种解法,这回学习了下二维的ST算法,感觉计算无比的巧妙,利用倍增思想保存一些矩形的最值,然后利用这些有交集的矩形来获得任何一个矩形的最值,整个算法达到 时间复杂度为O(n*n*logn*logn)-O(1),空间复杂度为O(n*n*logn*logn),基本上解决求最值问题,只是如果需要更改元素的值的话,只能用二维线段树来搞了= =

代码:

#include<cstdio>
#define min(a,b) (a<b?a:b)
#define N 310
int matrix[N][N];
int M[N][9][N][9];
int log_2(int n)
{
    int ret=0;
    while((1<<(ret+1))<n)++ret;
    return ret;
}
void ST(int n)
{
    int i,j,u,v;
    int logn=log_2(n);
    for(j=0;j<=logn;++j)
        for(v=0;v<=logn;++v)
            for(i=0;i+(1<<j)-1<n;++i)
                for(u=0;u+(1<<v)-1<n;++u)
                    if(j==0&&v==0)M[i][j][u][v]=matrix[i][u];
                    else if(v==0)M[i][j][u][v]=min(M[i][j-1][u][v],M[i+(1<<(j-1))][j-1][u][v]);
                    else M[i][j][u][v]=min(M[i][j][u][v-1],M[i][j][u+(1<<(v-1))][v-1]);
}
int get(int i,int j,int u,int v)
{
    int k=log_2(u-i+1);
    int t=log_2(v-j+1);
    int a=min(M[i][k][j][t],M[i][k][v-(1<<t)+1][t]);
    int b=min(M[u-(1<<k)+1][k][j][t],M[u-(1<<k)+1][k][v-(1<<t)+1][t]);
    return min(a,b);
}
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;
}
int main()
{
    int i,j,n,t,q,r1,c1,r2,c2;
    in(t);
    while(t--)
    {
        in(n);
        for(i=0;i<n;++i)
            for(j=0;j<n;++j)
                in(matrix[i][j]);
        ST(n);
        in(q);
        while(q--)
        {
            in(r1),in(c1),in(r2),in(c2);
            printf("%d\n",get(r1-1,c1-1,r2-1,c2-1));
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值