POJ2019 Cornfields 二维ST表

网址:https://vjudge.net/problem/POJ-2019

题意:

给出一个矩阵,求左下角坐标为$(x,y)$,长度为$b$的正方形的包含的数的最大值和最小值。

题解:

一、二维ST表:

一维$ST$表可以快速处理一维$RMQ$问题,这次是二维问题,好,那就上二维$ST$表,构造方法和一维的类似。开一个四维数组,第一维第三维管横行,第二维第四维管纵行即可(反过来也行)。然后处理完之后按照类似于一维$ST$表一样查询,查询四个小矩阵的最值就行,然后取最值,具体看代码。

AC代码:

#include <cstdio>
#include <cmath>
using namespace std;
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
int mat[255][255];
int maxn[255][255][8][8];
int minn[255][255][8][8];
int maxm(int a,int b,int c,int d)
{
    if(a<b)
        a=b;
    if(a<c)
        a=c;
    if(a<d)
        a=d;
    return a;
}
int minm(int a,int b,int c,int d)
{
    if(a>b)
        a=b;
    if(a>c)
        a=c;
    if(a>d)
        a=d;
    return a;
}
void init(int n,int m)
{
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
            scanf("%d",&mat[i][j]);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
        {
            maxn[i][j][0][0]=mat[i][j];
            minn[i][j][0][0]=mat[i][j];
            //printf("%d %d\n",maxn[i][j][0][0],minn[i][j][0][0]);
        }
    for(int k=0;(1<<k)<=n;++k)
        for(int l=0;(1<<l)<=m;++l)
            if(k+l)
                for(int i=1;i+(1<<k)-1<=n;++i)
                    for(int j=1;j+(1<<l)-1<=m;++j)
                    {
                        if(l)
                            maxn[i][j][k][l]=max(maxn[i][j][k][l-1],maxn[i][j+(1<<(l-1))][k][l-1]),
                            minn[i][j][k][l]=min(minn[i][j][k][l-1],minn[i][j+(1<<(l-1))][k][l-1]);
                        if(k)
                            maxn[i][j][k][l]=max(maxn[i][j][k-1][l],maxn[i+(1<<(k-1))][j][k-1][l]),
                            minn[i][j][k][l]=min(minn[i][j][k-1][l],minn[i+(1<<(k-1))][j][k-1][l]);
                    }
}
int maxquery(int l,int r,int x,int y)
{
    int a=log2(r-l+1);
    int b=log2(y-x+1);
    return maxm(maxn[l][x][a][b],maxn[r-(1<<a)+1][x][a][b],
        maxn[l][y-(1<<b)+1][a][b],maxn[r-(1<<a)+1][y-(1<<b)+1][a][b]);
}
int minquery(int l,int r,int x,int y)
{
    int a=log2(r-l+1);
    int b=log2(y-x+1);
    return minm(minn[l][x][a][b],minn[r-(1<<a)+1][x][a][b],
        minn[l][y-(1<<b)+1][a][b],minn[r-(1<<a)+1][y-(1<<b)+1][a][b]);
}
int main()
{
    int n,b,k,a,c;
    scanf("%d%d%d",&n,&b,&k);
    init(n,n);
    for(int i=0;i<k;++i)
    {
        scanf("%d%d",&a,&c);
        printf("%d\n",maxquery(a,a+b-1,c,c+b-1)-minquery(a,a+b-1,c,c+b-1));
    }
    return 0;
}

二、单调队列:

见以下博客,同类型题目,可照搬:

https://www.cnblogs.com/Aya-Uchida/p/11332856.html

原文地址:https://www.cnblogs.com/Aya-Uchida/p/11332822.html

时间: 2024-10-25 16:59:56

POJ2019 Cornfields 二维ST表的相关文章

[poj2019]Cornfields(二维RMQ)

题意:给你一个n*n的矩阵,让你从中圈定一个小矩阵,其大小为b*b,有q个询问,每次询问告诉你小矩阵的左上角,求小矩阵内的最大值和最小值的差. 解题关键:二维st表模板题. 预处理复杂度:$O({n^2}\log n)$ 查询复杂度:$O(n)$ 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdlib> 5 #include<iostream>

二维st表,一种暴力但却快速的二维RMQ利器

先上例题:[HAOI2007]理想的正方形 大部分人都用单调队列,但我不会.首先我们可以暴力枚举所有的可能的正方形,每次我们需要查询RMQ,如果用朴素的方法总复杂度就会变成N^4,你不T谁T 那怎么办,总不可能写正解吧,我们可以用二维st表,预处理N^2logN,每次O(1)查询,N^2水过. 注意,强制类型转换要用大括号括起要转换的东西,例如 (int)(log(n)/log(2)); Code: #include<iostream> #include<cstdio> #incl

POJ2019:二维ST算法解决静态方阵最值问题

我们其实是很有必要把ST算法拓展到二维的,因为二维的RMQ问题还是不少的 int N,B,K; int mm[505]; int val[maxn][maxn]; int dpmin[maxn][maxn][8][8]; int dpmax[maxn][maxn][8][8]; 这里的N是方阵的长宽,此处是正方形题目,然后mm是预处理出来的,方便计算指数 dpmin和dpmax就是预处理数组了 然后看一下开局预处理: void initRMQ(int n,int m) { for(int i=1

Codeforces Round #371 (Div. 1) D - Animals and Puzzle 二维ST表 + 二分

D - Animals and Puzzle #include<bits/stdc++.h> #define LL long long #define fi first #define se second #define mk make_pair #define PII pair<int, int> #define PLI pair<LL, int> #define ull unsigned long long using namespace std; const in

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

二维 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&

HDU2888 二维ST

以前写过一个一维的,今晚用了好久跟据那个一维的改成了二维然后做了这题 ST算法:求指定区间内的最值 一维: 设 d[i][j] 表示[i,i+1,...,i+2^j-1]这个区间内的最值然后给出的任意一个区间都可以用两个这样的区间来表示(有重叠部分)然后只需要对两个区间求一个max就ok d[i][j]可以通过递推得到 二维:设d[i][j][k][l]表示由[i,i+1,....,i+2^j-1]行和[k,k+1,....,k+2^l-1]列组成的子矩阵内的最大值,然后可以由四部分放一起表示出

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

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

poj2019(二维RMQ)

题目连接:http://poj.org/problem?id=2019 只是增加一个维度,类比一维即可. 1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<algorithm> 5 using namespace std; 6 const int maxn=270; 7 int p[maxn][maxn]; 8 int pmax[maxn][maxn][20]; 9 int