zoukankan      html  css  js  c++  java
  • LightOJ 1081 Square Queries(二维RMQ降维)

    Little Tommy is playing a game. The game is played on a 2D N x N grid. There is an integer in each cell of the grid. The rows and columns are numbered from 1 to N.

    At first the board is shown. When the user presses a key, the screen shows three integers I, J, Swhich designates a square (I, J) to (I+S-1, J+S-1) in the grid. The player has to predict the largest integer found in this square. The user will be given points based on the difference between the actual result and the given result.

    Tommy doesn't like to lose. So, he made a plan, he will take help of a computer to generate the result. But since he is not a good programmer, he is seeking your help.

    Input

    Input starts with an integer T (≤ 3), denoting the number of test cases.

    The first line of a case is a blank line. The next line contains two integers N (1 ≤ N ≤ 500), Q (0 ≤ Q ≤ 50000). Each of the next N lines will contain N space separated integers forming the grid. All the integers will be between 0 and 105.

    Each of the next Q lines will contain a query which is in the form I J S (1 ≤ I, J ≤ N and 1 ≤ I + S, J + S < N and S > 0).

    Output

    For each test case, print the case number in a single line. Then for each query you have to print the maximum integer found in the square whose top left corner is (I, J) and whose bottom right corner is (I+S-1, J+S-1).

    Sample Input

    1

    4 5

    67 1 2 3

    8 88 21 1

    89 12 0 12

    5 5 5 5

    1 1 2

    1 3 2

    3 3 2

    1 1 4

    2 2 3

    Sample Output

    Case 1:

    88

    21

    12

    89

    88

    题意:

    给定一个n*n(n<=500)的矩阵(即是正方形),每次询问以(x,y)为左上角,边长为s的正方形区域内的最大值。

    题解:

    用一般的二维RMQ预处理会超时。

    因为所给矩阵是为正方形,所以我们每次只用存储正方形即可。

    dp[i][j][k]:以(i,j)为左上角,边长为2^k的正方形区域内的最大值,每次倍增只需把大正方形拆成4个小正方形就好了。

    #include<algorithm>
    #include<iostream>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    const int MAX=505;
    int dp[MAX][MAX][10],mm[MAX],val[MAX][MAX];
    void initrmq(int n)
    {
        int lt,lb,rt,rb;
        for(int k=0;k<=mm[n];k++)
            for(int i=1;i+(1<<k)-1<=n;i++)
                for(int j=1;j+(1<<k)-1<=n;j++)
                    if(k==0)
                        dp[i][j][k]=val[i][j];
                    else
                    {
                        lt=dp[i][j][k-1];                  //左上角
                        lb=dp[i+(1<<k-1)][j][k-1];         //左下角
                        rt=dp[i][j+(1<<k-1)][k-1];         //右上角
                        rb=dp[i+(1<<k-1)][j+(1<<k-1)][k-1];//右下角
                        dp[i][j][k]=max(max(lt,lb),max(rt,rb));
                    }
    }
    int rmq(int x,int y,int s)
    {
        if(s==1)return val[x][y];
        int k=mm[s];
        int lt=dp[x][y][k];
        int lb=dp[x+s-(1<<k)][y][k];
        int rt=dp[x][y+s-(1<<k)][k];
        int rb=dp[x+s-(1<<k)][y+s-(1<<k)][k];
        return max(max(lt,lb),max(rt,rb));
    }
    int main()
    {
        int i,j,k,T;
        mm[0]=-1;
        for(i=1;i<=MAX;i++)
            mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1];
        scanf("%d",&T);
        for(int cas=1;cas<=T;cas++)
        {
            int n,q;
            scanf("%d%d",&n,&q);
            for(i=1;i<=n;i++)
                for(j=1;j<=n;j++)
                    scanf("%d",&val[i][j]);
            initrmq(n);
            printf("Case %d:
    ",cas);
            while(q--)
            {
                int x,y,s;
                scanf("%d%d%d",&x,&y,&s);
                printf("%d
    ",rmq(x,y,s));
            }
        }
        return 0;
    }
  • 相关阅读:
    【bzoj1176】[Balkan2007]Mokia
    【bzoj1503】[NOI2004]郁闷的出纳员
    C#设置和获取系统环境变量
    结伙创业指南及翻脸法则
    Unity3D_(游戏)卡牌03_选关界面
    Unity3D_(游戏)卡牌02_主菜单界面
    Unity3D_(游戏)卡牌01_启动屏界面
    Unity3D_(游戏)跳一跳超简单制作过程
    如何将项目托管到Github上
    Android_(游戏)打飞机06:后续
  • 原文地址:https://www.cnblogs.com/kannyi/p/9810695.html
Copyright © 2011-2022 走看看