RMQ问题小结

  by Wine93 2014.1.14

 

1.算法简介

RMQ问题可分成以下2种

(1)静态RMQ:ST算法

一旦给定序列确定后就不在更新,只查询区间最大(小)值!这类问题可以用倍增的ST算法进行预处理

预处理:O(nlogn)

查询:O(1)

(2)动态RMQ:线段树

要更新一些值,还有询问

更新:O(logn)

查询:O(logn)

2.相关题目

(1)静态RMQ

1.POJ 3264 Balanced Lineup(一维静态RMQ模板题) http://poj.org/problem?id=3264

题意:给定n(n<=50000)个数字,每次询问[l,r]内的最大值和最小值差

分析:裸的一维RMQ,用ST预处理!

# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std; # define N int log2[N];
int a[N],f[N][],g[N][]; //f:max g:min
void initRMQ(int a[],int n)
{
int i,j;
log2[]=;
for(i=;i<N;i++)
log2[i]=log2[i-]+!(i&(i-));
for(i=;i<=n;i++)
f[i][]=g[i][]=a[i];
for(j=;(<<j)<=n;j++)
for(i=;i+(<<j)-<=n;i++)
{
f[i][j]=max(f[i][j-],f[i+(<<j-)][j-]);
g[i][j]=min(g[i][j-],g[i+(<<j-)][j-]);
}
} int getmax(int l,int r)
{
int k=log2[r-l+];
return max(f[l][k],f[r-(<<k)+][k]);
} int getmin(int l,int r)
{
int k=log2[r-l+];
return min(g[l][k],g[r-(<<k)+][k]);
} int main()
{
int i,n,m,x,y;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(i=;i<=n;i++)
scanf("%d",&a[i]);
initRMQ(a,n);
for(i=;i<=m;i++)
{
scanf("%d%d",&x,&y);
printf("%d\n",getmax(x,y)-getmin(x,y));
}
}
return ;
}

POJ 3264

2.HDU 2888 Check Corners(二维静态RMQ模板题) http://acm.hdu.edu.cn/showproblem.php?pid=2888

题意:给定一个n*m (1<=m,n<=300)的矩阵!每次询问(r1,c1)为左上角,(r2,c2)为右下角的子矩形的最大值。

分析:裸的二维RMQ,用ST预处理即可!

# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std; # define N
# define M
int dp[N][N][M][M];
int log2[N];
int a[N][N],n,m,q; void initRMQ()
{
int i,j,k,l;
for(k=;(<<k)<=n&&k<=;k++)
for(l=;(<<l)<=m&&l<=;l++)
for(i=;i+(<<k)-<=n;i++)
for(j=;j+(<<l)-<=m;j++)
{
if(k==&&l==) dp[i][j][k][l]=a[i][j];
else if(k==) dp[i][j][k][l]=max(dp[i][j][k][l-],dp[i][j+(<<l-)][k][l-]);
else if(l==) dp[i][j][k][l]=max(dp[i][j][k-][l],dp[i+(<<k-)][j][k-][l]);
else
{
int a=max(dp[i][j][k-][l-],dp[i][j+(<<l-)][k-][l-]);
int b=max(dp[i+(<<k-)][j][k-][l-],dp[i+(<<k-)][j+(<<l-)][k-][l-]);
dp[i][j][k][l]=max(a,b);
}
}
} int getmax(int x1,int y1,int x2,int y2)
{
int k=log2[x2-x1+];
int l=log2[y2-y1+];
int a=max(dp[x1][y1][k][l],dp[x2-(<<k)+][y1][k][l]);
int b=max(dp[x1][y2-(<<l)+][k][l],dp[x2-(<<k)+][y2-(<<l)+][k][l]);
return max(a,b);
} int main()
{
int i,j,x1,y1,x2,y2;
log2[]=;
for(i=;i<N;i++)
log2[i]=log2[i-]+!((i-)&i);
while(scanf("%d%d",&n,&m)!=EOF)
{
for(i=;i<=n;i++)
for(j=;j<=m;j++)
scanf("%d",&a[i][j]);
initRMQ();
scanf("%d",&q);
while(q--)
{
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
int ans=getmax(x1,y1,x2,y2);
int res=max(max(a[x1][y1],a[x1][y2]),max(a[x2][y1],a[x2][y2]));
printf("%d ",ans);
if(res==ans) printf("yes\n");
else printf("no\n");
}
}
return ;
}

HDU 2888

3.LightOJ 1081 Square Queries(二维静态RMQ降维)  http://www.lightoj.com/volume_showproblem.php?problem=1081

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

分析:如果用一般的二维RMQ预处理,时间复杂度为n*n*logn*logn(约2000万),会超时!因为查询区域为正方形,我们只要每次都存储正方形就行了!

Max[i][j][k]:以(i,j)为左上角,边长为2^k区域内的最大值,每次倍增把大正方形拆成4个小正方形即可!

# include<map>
# include<set>
# include<cmath>
# include<queue>
# include<stack>
# include<vector>
# include<string>
# include<cstdio>
# include<cstring>
# include<iostream>
# include<algorithm>
# include<functional>
using namespace std; typedef pair<int,int> PII;
# define MOD
# define LL long long
# define pb push_back
# define F first
# define S second
# define N
# define M
int Max[N][N][M],Log2[N];
int a[N][N]; void initLog() //初始化Log2数组
{
int i;
Log2[]=-;
for(i=;i<N;i++)
Log2[i]=Log2[i-]+!(i&i-);
} void initRMQ(int n)
{
int i,j,k,lu,ld,ru,rd;
for(k=;(<<k)<=n;k++)
for(i=;i+(<<k)-<=n;i++)
for(j=;j+(<<k)-<=n;j++)
{
if(k==) Max[i][j][k]=a[i][j];
else
{
lu=Max[i][j][k-]; //左上角
ld=Max[i+(<<k-)][j][k-]; //左下角
ru=Max[i][j+(<<k-)][k-]; //右上角
rd=Max[i+(<<k-)][j+(<<k-)][k-]; //右下角
Max[i][j][k]=max(max(lu,ld),max(ru,rd));
}
}
} int Query(int x,int y,int l)
{
if(l==) return a[x][y]; //注意
int k=Log2[l];
int lu=Max[x][y][k];
int ld=Max[x+l-(<<k)][y][k];
int ru=Max[x][y+l-(<<k)][k];
int rd=Max[x+l-(<<k)][y+l-(<<k)][k];
return max(max(lu,ld),max(ru,rd));
} int main()
{
//freopen("in.txt","r",stdin);
initLog();
int cas,T,i,j,n,m,x,y,l;
scanf("%d",&T);
for(cas=;cas<=T;cas++)
{
scanf("%d%d",&n,&m);
for(i=;i<=n;i++)
for(j=;j<=n;j++)
scanf("%d",&a[i][j]);
initRMQ(n);
printf("Case %d:\n",cas);
while(m--)
{
scanf("%d%d%d",&x,&y,&l);
printf("%d\n",Query(x,y,l));
}
}
return ;
}

Lightoj 1081

4.POJ 3368 Frequent values

题意:给定n(n<=100000)个数,每次询问一个区间内重复数字的最大次数

5.POJ 2452 Sticks Problem

6.HDU 3486 Interviewe

(2)动态RMQ

1.HDU 1754 I Hate It (一维动态RMQ模板题)

2.Uva 11297 Census(二维动态RMQ模板题)

3.HDU 4819 Mosaic (13年长春现场)

4.NBU 2475 Survivors 
5.BUAA 724 晴天小猪的神题

 

[数据结构]RMQ问题小结的更多相关文章

  1. 数据结构——RMQ

    RMQ 今天临放学前终于是学会了RMQ,特此写一篇题解来缅怀 RMQ是一种数据结构,用途是查询区间内最大值或最小值 或者你所要求的任意条件,主要思想是二进制的思想,其中还用到了dp的思想, 是一种非常 ...

  2. 数据结构(RMQ):POJ 3624 Balanced Lineup

    Balanced Lineup   Description For the daily milking, Farmer John's N cows (1 ≤ N ≤ 50,000) always li ...

  3. 数据结构RMQ

    RMQ算法介绍 RMQ算法全称为(Range Minimum/Maximum Query)意思是给你一个长度为n的数组A,求出给定区间的最值的下标.当然我们可以采用枚举,但是我们也可以使用线段树来优化 ...

  4. 数据结构(RMQ):UVAoj 11235 Frequent values

    Frequent values You are given a sequence of n integers a1 , a2 , ... , an in non-decreasing order. I ...

  5. uva 11235

    数据结构 RMQ算法   左右左右   写得有点晕了 ..... /****************************************************************** ...

  6. RMQ 数据结构

    RMQ 常用的数据结构之一 直接上代码 马克好来 是个好板子 #include <stdio.h> #define min(a,b) a<b ? a : b ],d[][]; voi ...

  7. [数据结构]KMP小结

    KMP小结   By Wine93 2013.9 1.学习链接: http://www.matrix67.com/blog/archives/115 2.个人小结 1.KMP在字符串中匹配中起着巨大作 ...

  8. 【暑假】[实用数据结构]范围最小值问题(RMQ)

    范围最小值问题: 提供操作: Query(L,R):计算min{AL ~ AR } Sparse-Table算法: 定义d[i][j]为从i开始长度为2j的一段元素的最小值.所以可以用递推的方法表示. ...

  9. OpenJudge_cdqz 数据结构版块小结

    题目整理 Challenge 0  随机线性存储表-easy Challenge 1  链表数组-easy Challenge 2  可持久化Treap的可持久化运用-hard Challenge 3 ...

随机推荐

  1. 无法启动T-SQL 调试

    问题详情 解决办法 1.要在服务器本机,不要远程 2.用实例名,不要用.或者local 3.以Windows身份验证的administrator或者sqlserver身份验证的sa登录

  2. 创建PO/SO

    IF P_ZY EQ 'X'."直营订单 调拨单 PERFORM FRM_INIT_PO_HEADER. PERFORM FRM_INIT_PO_ITEM. PERFORM FRM_INIT ...

  3. BZOJ3996 [TJOI2015]线性代数

    就是求$D = A \times B \times A^T - C \times A^T$ 展开也就是$$D = \sum_{i, j} A_i * A_j * B_{i, j} - \sum_{i} ...

  4. 二模 (9)day1

    第一题: 题目大意: 给出一个n位01串,要么不动它,要么把它删掉一个字符,要么插入一个字符(0或1),要么把一个1变成0,.使得有1的位置号的总和是n+1的倍数,或者是0. 解题过程: 1.直接枚举 ...

  5. NOIP 2003解题报告

    第一题(神经网络): 题目大意,给出一些点,每个点都有2个值,c和u,给出一些有向边,权值为w.入度为0的点的c已知,其它点的c未知,每个入度不为0的点node的c等于sum(c[k]*w[k][no ...

  6. ASP.NET MVC过滤器(一)

    MVC过滤器是加在 Controller 或 Action 上的一种 Attribute,通过过滤器,MVC 网站在处理用户请求时,可以处理一些附加的操作,如:用户权限验证.系统日志.异常处理.缓存等 ...

  7. Struts2 的验证

    概述 一个健壮的 web 应用程序必须确保用户输入是合法.有效的. Struts2 的输入验证 –基于 XWork Validation Framework 的声明式验证:Struts2 提供了一些基 ...

  8. AOP面向切面编程

    1.AOP Aop(aspect object programming)面向切面编程 功能: 让关注点代码与业务代码分离! 关注点 重复代码就叫做关注点: 切面 关注点形成的类,就叫切面(类)! 面向 ...

  9. Hibernate中的集合映射

    1.定义实体 public class User { private int userId; private String userName; private Set<String> ad ...

  10. 我认为测试应该掌握的SQL语句

    最近在学习Oracle,对测试人员而言必须掌握两种语言:第一种是DML,数据操纵语言 (Data Manipulation Language) 是SQL语言中,负责对数据库对象运行数据访问工作的指令集 ...