【模板】RMQ(计算区间最值)
①一维RMQ
(1) dp[i,j] 表示从第i个数起连续2j个数中的(最大值min、最小值max、最大公约数gcd……),通过更改下列代码中的红色函数即可实现。
(2) b数组放置所需查询的数列。
const int MAX=;
int dp[MAX][];
int mm[MAX];
void initrmq(int n,int b[])
{
mm[]=-;
for(int i=;i<=n;i++)
{
mm[i]=((i&(i-))==)?mm[i-]+:mm[i-];
dp[i][]=b[i];
}
for(int j=;j<=mm[n];j++)
for(int i=;i+(<<j)-<=n;i++)
dp[i][j]=max(dp[i][j-],dp[i+(<<(j-))][j-]);
}
ll rmq(int x,int y)
{
int k=mm[y-x+];
return max(dp[x][k],dp[y-(<<k)+][k]);
}
②二维RMQ
给定一个n*m矩阵,每次询问左上角(r1,c1)到右下角(r2,c2)的子矩形中的(最大值min、最小值max、最大公约数gcd……)并输出。如果每次所询问的四个角有符合条件的数,输出yes,否则输出no。
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<map>
using namespace std;
typedef long long ll;
const int MAX=;
int val[MAX][MAX];
int dp[MAX][MAX][][];//最大值
int mm[MAX];
void initRMQ(int n,int m)//m*n的矩阵
{
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
dp[i][j][][]=val[i][j];
for(int ii=;ii<=mm[n];ii++)
for(int jj=;jj<=mm[m];jj++)
if(ii+jj)
for(int i=;i+(<<ii)-<=n;i++)
for(int j=;j+(<<jj)-<=m;j++)
if(ii)dp[i][j][ii][jj]=max(dp[i][j][ii-][jj],dp[i+(<<(ii-))][j][ii-][jj]);
else dp[i][j][ii][jj]=max(dp[i][j][ii][jj-],dp[i][j+(<<(jj-))][ii][jj-]);
}
int rmq(int x1,int y1,int x2,int y2)//所查询矩形区间内的最大值 左上角(x1,y1) -> 右上角(x2,y2)
{
int k1=mm[x2-x1+];
int k2=mm[y2-y1+];
x2=x2-(<<k1)+;
y2=y2-(<<k2)+;
return max(max(dp[x1][y1][k1][k2],dp[x1][y2][k1][k2]),max(dp[x2][y1][k1][k2],dp[x2][y2][k1][k2]));
}
int main()
{
mm[]=-;
for(int i=;i<=MAX;i++)
mm[i]=((i&(i-))==)?mm[i-]+:mm[i-];
int n,m,Q;
int r1,c1,r2,c2;
while(scanf("%d%d",&n,&m)==)
{
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
scanf("%d",&val[i][j]);
initRMQ(n,m);
scanf("%d",&Q);
while(Q--)
{
scanf("%d%d%d%d",&r1,&c1,&r2,&c2);//左上角(r1,c1) -> 右上角(r2,c2)
if(r1>r2)swap(r1,r2);
if(c1>c2)swap(c1,c2);
int tmp=rmq(r1,c1,r2,c2);
printf("%d ",tmp);
if(tmp==val[r1][c1]||tmp==val[r1][c2]||tmp==val[r2][c1]||tmp==val[r2][c2])
printf("yes\n");
else printf("no\n");
}
}
return ;
}
③二维RMQ降维
给定一个n*n(n<=500)的矩阵(即是正方形),每次询问以(x,y)为左上角,边长为s的正方形区域内的最大值。
dp[i][j][k]:以(i,j)为左上角,边长为2^k的正方形区域内的最大值。
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;
const int MAX=;
int dp[MAX][MAX][],mm[MAX],val[MAX][MAX];
void initrmq(int n)
{
int lt,lb,rt,rb;
for(int k=;k<=mm[n];k++)
for(int i=;i+(<<k)-<=n;i++)
for(int j=;j+(<<k)-<=n;j++)
if(k==)
dp[i][j][k]=val[i][j];
else
{
lt=dp[i][j][k-]; //左上角
lb=dp[i+(<<k-)][j][k-]; //左下角
rt=dp[i][j+(<<k-)][k-]; //右上角
rb=dp[i+(<<k-)][j+(<<k-)][k-];//右下角
dp[i][j][k]=max(max(lt,lb),max(rt,rb));
}
}
int rmq(int x,int y,int s)
{
if(s==)return val[x][y];
int k=mm[s];
int lt=dp[x][y][k];
int lb=dp[x+s-(<<k)][y][k];
int rt=dp[x][y+s-(<<k)][k];
int rb=dp[x+s-(<<k)][y+s-(<<k)][k];
return max(max(lt,lb),max(rt,rb));
}
int main()
{
int i,j,k,T;
mm[]=-;
for(i=;i<=MAX;i++)
mm[i]=((i&(i-))==)?mm[i-]+:mm[i-];
scanf("%d",&T);
for(int cas=;cas<=T;cas++)
{
int n,q;
scanf("%d%d",&n,&q);
for(i=;i<=n;i++)
for(j=;j<=n;j++)
scanf("%d",&val[i][j]);
initrmq(n);
printf("Case %d:\n",cas);
while(q--)
{
int x,y,s;
scanf("%d%d%d",&x,&y,&s);
printf("%d\n",rmq(x,y,s));
}
}
return ;
}
【模板】RMQ(计算区间最值)的更多相关文章
- ST表 求 RMQ(区间最值)
RMQ即Range Minimum/Maximun Query,中文意思:查询一个区间的最小值/最大值 比如有这样一个数组:A{3 2 4 5 6 8 1 2 9 7},然后问你若干问题: 数组A下标 ...
- 【RMQ】 区间最值查询详解
1. 概述 RMQ(Range Minimum/Maximum Query),即区间最值查询,是指这样一个问题:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A ...
- hdu3183 rmq求区间最值的下标
两个月前做的题,以后可以看看,是rmq关于求区间最值的下标 /* hdu3183 终点 给一个整数,可以删除m位,留下的数字形成一个新的整数 rmq 取n-m个数,使形成的数最小 */ #includ ...
- 基于稀疏表(Sparse Table)的RMQ(区间最值问题)
在RMQ的其他实现方法中,有一种叫做ST的算法比较常见. [构建] dp[i][j]表示的是从i起连续的2j个数xi,xi+1,xi+2,...xi+2j-1( 区间为[i,i+2j-1] )的最值. ...
- 【模板】 RMQ求区间最值
RMQ RMQ简单来说就是求区间的最大值(最小值) 核心算法:动态规划 RMQ(以下以求最大值为例) F[i,j]表示 从 i 开始 到i+2j -1这个区间中的最大值 状态转移方程 F[i,j]=m ...
- RMQ求区间最值 nlog(n)
转载于:http://blog.csdn.net/xuzengqiang/article/details/7350465 RMQ算法全称为(Range Minimum/Maximum Query)意思 ...
- RMQ算法区间最值
问题类型:是多次询问一个大区间里子区间的最值问题 dp + 位运算的思想处理 rmax[i][j]表示从i开始到i + 2^j - 1的区间里的最大值dp[i][j] ==== (i,i + 2^j ...
- HDU 5919 - Sequence II (2016CCPC长春) 主席树 (区间第K小+区间不同值个数)
HDU 5919 题意: 动态处理一个序列的区间问题,对于一个给定序列,每次输入区间的左端点和右端点,输出这个区间中:每个数字第一次出现的位子留下, 输出这些位子中最中间的那个,就是(len+1)/2 ...
- RMQ(模板 ST 区间最值,频繁的间隔时间)
PS: 介绍:http://blog.csdn.net/liang5630/article/details/7917702 RMQ算法.是一个高速求区间最值的离线算法,预处理时间复杂度O(n*log( ...
随机推荐
- FCKeditor文本编辑器的使用方法
FCKeditor是一个功能强大支持所见即所得功能的文本编辑器,可以为用户提供微软office软件一样的在线文档编辑服务. 它不需要安装任何形式的客户端,兼容绝大多数主流浏览器,支持ASP.Net.A ...
- 简单理解C#中的抽象工厂模式是什么概念!
抽象工厂模式向客户端提供一个接口,使得客户端在不必指定具体类型的情况下,创建多个产品族中的对象.本文采取的仍然是接着以前的那个快餐店的例子.现在,快餐店经常良好,逐渐发展壮大,为了适合不同地方人的饮食 ...
- ArcGIS 编程中对接口的理解
学习AO,最重要的是理解“接口”这个概念.接口是什么?有什么具体作用?在多种计算机高级语言中,都可以看到“接口”这个术语,但基本上每一本书对“为什么使用接口”等重要文都都“语焉不详”,使得初学者往往不 ...
- 二十一、如何导入svg图片
svg就相当于字体,如何将生成的svg导入到自己的项目中去呢? 1.将类似下面的文件放入自己的项目中: 2.生成的svg中有一个style.css文件,将里面的内容拷贝到你的css中,然后更改上图的路 ...
- 微信证书 javax.net.ssl.SSLException: java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty
这几天在做微信退款接口,按照api写完之后,在本地测试了下没有问题,于是交给测试让他们在测试环境开测.他们说退款没有成功,感觉去查日志,发现后台报了 javax.net.ssl.SSLExceptio ...
- Python pymysql模块学习心得
PyMySQL包含了一个纯Python的MySQL客户端的库,它的目的是用来替换MySQLdb,并且工作在CPython,PyPy和IronPython. PyMySQL官方地址:https://py ...
- 使用pdb调试python脚本
pdb 是 python 自带的一个包,为 python 程序提供了一种交互的源代码调试功能,主要特性包括设置断点.单步调试.进入函数调试.查看当前代码.查看栈片段.动态改变变量的值等.pdb 提供了 ...
- MySQL案例01:Last_SQL_Errno: 1755 Cannot execute the current event group in the parallel mode
周五同事监控报警,有个MySQL从库复制状态异常,让我帮忙排查下,经过排查发现是MySQL5.6并行复制的一个Bug所致,具体处理过程如下: 一.错误信息 登录mysql从库服务器,检查复制状态 my ...
- .Net中初探Redis
一.简介 Redis是著名的NOSQL数据库,本质就是存储键值对结构的数据,为存储键值对数据做了优化,在大型网站中应用很多.Redis提供了数据的自动过期处理,因此适合存储临时数据. 和Redis类似 ...
- python调用chrome打开指定网址
#!/usr/bin/python # -*- coding:utf-8 -*- import os f = open("chrome_cmd_path.txt") chrome ...