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;i<=n;i++)
    for(int j=1;j<=m;j++)
        dpmin[i][j][0][0]=dpmax[i][j][0][0]=val[i][j];
    for(int ii=0;ii<=mm[n];ii++)
    for(int jj=0;jj<=mm[m];jj++)
    if(ii+jj)
    for(int i=1;i+(1<<ii)-1<=n;i++)
    for(int j=1;j+(1<<jj)-1<=m;j++)
    {
        if(ii)
        {
            dpmin[i][j][ii][jj] = min(dpmin[i][j][ii-1][jj],dpmin[i+(1<<(ii-1))][j][ii-1][jj]);
            dpmax[i][j][ii][jj] = max(dpmax[i][j][ii-1][jj],dpmax[i+(1<<(ii-1))][j][ii-1][jj]);
        }
        else
        {
            dpmin[i][j][ii][jj] = min(dpmin[i][j][ii][jj-1],dpmin[i][j+(1<<(jj-1))][ii][jj-1]);
            dpmax[i][j][ii][jj] = max(dpmax[i][j][ii][jj-1],dpmax[i][j+(1<<(jj-1))][ii][jj-1]);
        }
    }
}

我们看预处理的时候还是比较明朗的,当然别忘了在主函数把mm初始化好

    mm[0]=-1;
    for(int i=1;i<=500;i++)
        mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1];

然后就是求最大值和最小值的函数了,这里,一定要仔细地去写,很容易写错:

int rmq1(int x1,int y1,int x2,int y2)  //max
{
    int k1=mm[x2-x1+1];
    int k2=mm[y2-y1+1];
    x2=x2-(1<<k1)+1;
    y2=y2-(1<<k2)+1;
    return max(max(dpmax[x1][y1][k1][k2],dpmax[x1][y2][k1][k2]),max(dpmax[x2][y1][k1][k2],dpmax[x2][y2][k1][k2]));
}
int rmq2(int x1,int y1,int x2,int y2)
{
    int k1=mm[x2-x1+1];
    int k2=mm[y2-y1+1];
    x2=x2-(1<<k1)+1;
    y2=y2-(1<<k2)+1;
    return min(min(dpmin[x1][y1][k1][k2],dpmin[x1][y2][k1][k2]),min(dpmin[x2][y1][k1][k2],dpmin[x2][y2][k1][k2]));
}

这个式子确实很长的

最后给出题目完整的实现:

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 const int maxn=255;
 5 int N,B,K;
 6 int mm[505];
 7 int val[maxn][maxn];
 8 int dpmin[maxn][maxn][8][8];
 9 int dpmax[maxn][maxn][8][8];
10 void initRMQ(int n,int m)
11 {
12     for(int i=1;i<=n;i++)
13     for(int j=1;j<=m;j++)
14         dpmin[i][j][0][0]=dpmax[i][j][0][0]=val[i][j];
15     for(int ii=0;ii<=mm[n];ii++)
16     for(int jj=0;jj<=mm[m];jj++)
17     if(ii+jj)
18     for(int i=1;i+(1<<ii)-1<=n;i++)
19     for(int j=1;j+(1<<jj)-1<=m;j++)
20     {
21         if(ii)
22         {
23             dpmin[i][j][ii][jj] = min(dpmin[i][j][ii-1][jj],dpmin[i+(1<<(ii-1))][j][ii-1][jj]);
24             dpmax[i][j][ii][jj] = max(dpmax[i][j][ii-1][jj],dpmax[i+(1<<(ii-1))][j][ii-1][jj]);
25         }
26         else
27         {
28             dpmin[i][j][ii][jj] = min(dpmin[i][j][ii][jj-1],dpmin[i][j+(1<<(jj-1))][ii][jj-1]);
29             dpmax[i][j][ii][jj] = max(dpmax[i][j][ii][jj-1],dpmax[i][j+(1<<(jj-1))][ii][jj-1]);
30         }
31     }
32 }
33 int rmq1(int x1,int y1,int x2,int y2)  //max
34 {
35     int k1=mm[x2-x1+1];
36     int k2=mm[y2-y1+1];
37     x2=x2-(1<<k1)+1;
38     y2=y2-(1<<k2)+1;
39     return max(max(dpmax[x1][y1][k1][k2],dpmax[x1][y2][k1][k2]),max(dpmax[x2][y1][k1][k2],dpmax[x2][y2][k1][k2]));
40 }
41 int rmq2(int x1,int y1,int x2,int y2)
42 {
43     int k1=mm[x2-x1+1];
44     int k2=mm[y2-y1+1];
45     x2=x2-(1<<k1)+1;
46     y2=y2-(1<<k2)+1;
47     return min(min(dpmin[x1][y1][k1][k2],dpmin[x1][y2][k1][k2]),min(dpmin[x2][y1][k1][k2],dpmin[x2][y2][k1][k2]));
48 }
49 int main()
50 {
51     mm[0]=-1;
52     for(int i=1;i<=500;i++)
53         mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1];
54     while(scanf("%d%d%d",&N,&B,&K)==3)
55     {
56         for(int i=1;i<=N;i++)
57         for(int j=1;j<=N;j++)
58             scanf("%d",&val[i][j]);
59         initRMQ(N,N);
60         int x,y;
61         while(K--)
62         {
63             scanf("%d%d",&x,&y);
64             printf("%d\n",rmq1(x,y,x+B-1,y+B-1)-rmq2(x,y,x+B-1,y+B-1));
65         }
66     }
67     return 0;
68 }

原文地址:https://www.cnblogs.com/aininot260/p/9379833.html

时间: 2024-12-26 15:40:32

POJ2019:二维ST算法解决静态方阵最值问题的相关文章

POJ2019 Cornfields 二维ST表

网址:https://vjudge.net/problem/POJ-2019 题意: 给出一个矩阵,求左下角坐标为$(x,y)$,长度为$b$的正方形的包含的数的最大值和最小值. 题解: 一.二维ST表: 一维$ST$表可以快速处理一维$RMQ$问题,这次是二维问题,好,那就上二维$ST$表,构造方法和一维的类似.开一个四维数组,第一维第三维管横行,第二维第四维管纵行即可(反过来也行).然后处理完之后按照类似于一维$ST$表一样查询,查询四个小矩阵的最值就行,然后取最值,具体看代码. AC代码:

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

Cornfields poj2019 二维RMQ

Cornfields Time Limit:1000MS     Memory Limit:30000KB     64bit IO Format:%I64d & %I64u Submit Status 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

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

android利用zbar二维码扫描-(解决中文乱码及扫描区域定义)

写在最前(这是对上一篇博文的问题做的更新[android利用zbar二维码扫描]) project下载   zbarLib编译project  project下载0积分 bug 在2.3的系统中Holder须要设置type,否则会黑屏(感谢网友[(α ⒎待sんа)294439435]) com.example.qu.MainActivity的第50行mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 今天发现 在com.exampl

Match:Milking Grid(二维kmp算法)(POJ 2185)

奶牛矩阵 题目大意:给定一个矩阵,要你找到一个最小的矩阵,这个矩阵的无限扩充的矩阵包含着原来的矩阵 思路:乍一看这一题确实很那做,因为我们不知道最小矩阵的位置,但是仔细一想,如果我们能把矩阵都放在左上角该多好,这样一来这一题好像又是循环数组那个样子了(二维的). 而事实上我们确实可以把所有情况都放在左上角,因为矩阵里面的元素的相对位置是不变的,这样一来我们就可以把矩阵看成都是一些元素从左上角往右下角扩充.那么现在问题就又回到了循环节的问题上了,我们可以把矩阵看成是很多很多个字符串组成,我们要找的

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]列组成的子矩阵内的最大值,然后可以由四部分放一起表示出

前端QRCode.js生成二维码(解决长字符串模块和报错问题)

QRCode 用法 1.使用npm安装到你的项目中 npm install qrcode2 --save 使用commonjs或者es6模块方式导入 var QRCode = require('qrcode2'); // 或者 import QRCode from 'qrcode2'; 3 . 实例化QRCode对象 new QRCode(document.getElementById('qrcode'), 'http://www.baidu.com'); // // 或者配置一些选项 var

写一个二维数组排序算法函数,能够具有通用性,可以调用php内置函数

下面代码没有认真看: <?php //二维数组排序, $arr是数据,$keys是排序的健值,$order是排序规则,1是升序,0是降序 function array_sort($arr, $keys, $order = 0) { if (!is_array($arr)) { return false; } $keysvalue = array(); foreach ($arr as $key => $val) { $keysvalue[$key] = $val[$keys]; } if ($