RMQ [POJ 2019] Cornfields

Cornfields

Time Limit: 1000MS   Memory Limit: 30000K
Total Submissions: 5516   Accepted: 2714

Description

FJ has decided to grow his own corn hybrid in order to help the cows make the best possible milk. To that end, he‘s looking to build the cornfield on the flattest piece of land he can find.

FJ has, at great expense, surveyed his square farm of N x N hectares (1 <= N <= 250). Each hectare has an integer elevation (0 <= elevation <= 250) associated with it.

FJ will present your program with the elevations and a set of K (1 <= K <= 100,000) queries of the form "in this B x B submatrix, what is the maximum and minimum elevation?". The integer B (1 <= B <= N) is the size of one edge of the square cornfield and is a constant for every inquiry. Help FJ find the best place to put his cornfield.

Input

* Line 1: Three space-separated integers: N, B, and K.

* Lines 2..N+1: Each line contains N space-separated integers. Line 2 represents row 1; line 3 represents row 2, etc. The first integer on each line represents column 1; the second integer represents column 2; etc.

* Lines N+2..N+K+1: Each line contains two space-separated integers representing a query. The first integer is the top row of the query; the second integer is the left column of the query. The integers are in the range 1..N-B+1.

Output

* Lines 1..K: A single integer per line representing the difference between the max and the min in each query.

Sample Input

5 3 1
5 1 2 6 3
1 3 5 2 7
7 2 4 6 1
9 9 8 6 5
0 6 9 3 9
1 2

Sample Output

5

Source

USACO 2003 March Green

矩形解法:

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
#define N 255

int n,b,k;
int val[N][N];
int mx[N][N][8][8];
int mi[N][N][8][8];

void ST(int n,int m)
{
    int i,j,r,c;
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=m;j++)
        {
            mx[i][j][0][0]=mi[i][j][0][0]=val[i][j];
        }
    }
    int kn=(int)(log(double(n))/log(2.0));
    int km=(int)(log(double(m))/log(2.0));
    for(i=0;i<=kn;i++)
    {
        for(j=0;j<=km;j++)
        {
            if(i==0 && j==0)  continue;
            for(r=1;r+(1<<i)-1<=n;r++)
            {
                for(c=1;c+(1<<j)-1<=m;c++)
                {
                    if(i==0)
                    {
                        mx[r][c][i][j]=max(mx[r][c][i][j-1],mx[r][c+(1<<(j-1))][i][j-1]);
                        mi[r][c][i][j]=min(mi[r][c][i][j-1],mi[r][c+(1<<(j-1))][i][j-1]);
                    }
                    else
                    {
                        mx[r][c][i][j]=max(mx[r][c][i-1][j],mx[r+(1<<(i-1))][c][i-1][j]);
                        mi[r][c][i][j]=min(mi[r][c][i-1][j],mi[r+(1<<(i-1))][c][i-1][j]);
                    }
                }
            }
        }
    }
}

int RMQ(int r1,int c1,int r2,int c2)
{
    int kr=(int)(log(double(r2-r1+1))/log(2.0));
    int kc=(int)(log(double(c2-c1+1))/log(2.0));

    int t1=mx[r1][c1][kr][kc];
    int t2=mx[r2-(1<<kr)+1][c1][kr][kc];
    int t3=mx[r1][c2-(1<<kc)+1][kr][kc];
    int t4=mx[r2-(1<<kr)+1][c2-(1<<kc)+1][kr][kc];

    int m1=mi[r1][c1][kr][kc];
    int m2=mi[r2-(1<<kr)+1][c1][kr][kc];
    int m3=mi[r1][c2-(1<<kc)+1][kr][kc];
    int m4=mi[r2-(1<<kr)+1][c2-(1<<kc)+1][kr][kc];

    return max(max(t1,t2),max(t3,t4))-min(min(m1,m2),min(m3,m4));
}

int main()
{
    int i,j;
    scanf("%d%d%d",&n,&b,&k);
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=n;j++)
        {
            scanf("%d",&val[i][j]);
        }
    }
    ST(n,n);
    while(k--)
    {
        int r1,c1,r2,c2;
        scanf("%d%d",&r1,&c1);
        r2=r1+b-1;
        c2=c1+b-1;
        printf("%d\n",RMQ(r1,c1,r2,c2));
    }
    return 0;
}

正方形解法

#include <stdio.h>
#include <iostream>
#include <math.h>
using namespace std;
#define inf 0x7fffffff
#define N 255
#define max(a,b) a>b?a:b
#define min(a,b) a<b?a:b

int n,b,k;
int val[N][N];
int mx[N][N][8];
int mi[N][N][8];

int getMax(int x,int y,int p)
{
    int res=-inf;
    res=max(res,mx[x][y][p]);
    if(x+(1<<p)<=n) res=max(res,mx[x+(1<<p)][y][p]);
    if(y+(1<<p)<=n) res=max(res,mx[x][y+(1<<p)][p]);
    if(x+(1<<p)<=n && y+(1<<p)<=n) res=max(res,mx[x+(1<<p)][y+(1<<p)][p]);
    return res;
}
int getMin(int x,int y,int p)
{
    int res=inf;
    res=min(res,mi[x][y][p]);
    if(x+(1<<p)<=n) res=min(res,mi[x+(1<<p)][y][p]);
    if(y+(1<<p)<=n) res=min(res,mi[x][y+(1<<p)][p]);
    if(x+(1<<p)<=n && y+(1<<p)<=n) res=min(res,mi[x+(1<<p)][y+(1<<p)][p]);
    return res;
}

void ST()
{
    int i,j,k;
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=n;j++)
        {
            mx[i][j][0]=mi[i][j][0]=val[i][j];
        }
    }
    int kn=(int)(log(n*1.0)/log(2.0));

    for(k=1;k<=kn;k++)
    {
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=n;j++)
            {
                mx[i][j][k]=getMax(i,j,k-1);
                mi[i][j][k]=getMin(i,j,k-1);
            }
        }
    }
}

int RMQMAX(int x,int y,int b)
{
    int p=(int)(log(b*1.0)/log(2.0));
    int res=-inf;
    res=max(res,mx[x][y][p]);
    if(x+b-(1<<p)<=n) res=max(res,mx[x+b-(1<<p)][y][p]);
    if(y+b-(1<<p)<=n) res=max(res,mx[x][y+b-(1<<p)][p]);
    if(x+b-(1<<p)<=n && y+b-(1<<p)<=n) res=max(res,mx[x+b-(1<<p)][y+b-(1<<p)][p]);
    return res;
}

int RMQMIN(int x,int y,int b)
{
    int p=(int)(log(b*1.0)/log(2.0));
    int res=inf;
    res=min(res,mi[x][y][p]);
    if(x+b-(1<<p)<=n) res=min(res,mi[x+b-(1<<p)][y][p]);
    if(y+b-(1<<p)<=n) res=min(res,mi[x][y+b-(1<<p)][p]);
    if(x+b-(1<<p)<=n && y+b-(1<<p)<=n) res=min(res,mi[x+b-(1<<p)][y+b-(1<<p)][p]);
    return res;
}

int main()
{
    int i,j;
    scanf("%d%d%d",&n,&b,&k);
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=n;j++)
        {
            scanf("%d",&val[i][j]);
        }
    }
    ST();
    while(k--)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        printf("%d\n",RMQMAX(x,y,b)-RMQMIN(x,y,b));
    }
    return 0;
}
时间: 2024-10-10 12:45:37

RMQ [POJ 2019] Cornfields的相关文章

POJ 2019 Cornfields 二维RMQ

题目来源:POJ 2019 Cornfields 题意:求正方形二维区间最大最小值的差 思路:直接二维ST搞 试模版而已 #include <cstdio> #include <algorithm> #include <cmath> using namespace std; const int maxn = 255; int dp[maxn][maxn][8][8]; int dp2[maxn][maxn][8][8]; int a[maxn][maxn]; int n

POJ 2019 Cornfields (RMQ?反正我暴力了)

[题意简述]:题目告诉我们很多数据,有N,表示这个农场的大小N*N,还有B,表示我们要测量的那个小正方形的大小B*B,还有K,代表我们要在这个N*N的农场上测几组数据.要测量的那个小正方形的左上角的坐标给你了,x和y.现在让我们求出在这个B*B的小正方形中最大的数值减去最小的数值结果是多少 [分析]:这本应是个二维的RMQ问题: http://blog.csdn.net/u013749862/article/details/39008855 下面是别人用RMQ的解法: http://kmplay

POJ 2019 Cornfields

相比以前的RMQ不同的是,这是一个二维的ST算法 #include<iostream> #include<cstring> #include<cstdio> #include<cmath> using namespace std; #define N 300 int minbest[8][8][N][N]; int maxbest[8][8][N][N]; ///int lg[N]; int getmax(int a,int b,int c,int d) {

POJ 2019 Cornfields 二维线段树的初始化与最值查询

模板到不行.. 连更新都没有.. .存个模板. 理解留到小结的时候再写. #include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <queue> #include <cmath> #include <stack> #include <map> #

Tarjan算法各种&amp;RMQ&amp; POJ 3694

关于tarjan 的思想可以在网上搜到,具体我也不太清楚,应该说自己理解也不深,下面是做题经验得到的一些模板. 其中有很多转载,包括BYVoid等,感谢让我转...望各路大神愿谅 有向图求连通分量的一般方法: 1 void Tarjan(u) { 2 dfn[u]=low[u]=++index 3 stack.push(u) 4 for each (u, v) in E { 5 if (v is not visted) { 6 tarjan(v) 7 low[u] = min(low[u], l

poj 2019 二维rmq *

题目大意:给出一个N*N矩形,每个格子上有一个价值.询问一个b*b的矩形在左上角的位置(x,y),(x+b-1,y+b-1)这一部分的最大值-最小值是多少. 模板题 1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 7 int val[255][255]; 8 int mm[255];

POJ 2019

简单的RMQ,可我怎么写都WA.不明白,找了一个和我相似的贴过了,要赶着去外婆家. #include <iostream> #include <algorithm> #include <cstring> #include <string> #include <cstdio> #include <cmath> #include <queue> #include <vector> #include <map&

二维 ST POJ 2019

题目大意:给你一个n*n的矩阵,每次给你一个点(x,y),以其为左上角,宽度为b的矩阵中最小的数值和最大数值的差是多少?  一共k个询问. 思路:简单的二维st. 定义dp(i,j,k,L)表示以(i,j)为左上角,宽度为(2^k, 2^L)的区间内的最大(小)值. //看看会不会爆int!数组会不会少了一维! //取物问题一定要小心先手胜利的条件 #include<cstdio> #include<cstring> #include<vector> #include&

POJ 2019 Power of Cryptography

技巧. #include<iostream> #include<cmath> using namespace std; double n,p; int main(){ while(cin>>n>>p){ cout<<pow(p,1/n)<<endl; } }