【RMQ问题】求数组区间最大值,NYOJ-1185-最大最小值
- 转自:http://blog.csdn.net/lilongherolilong/article/details/6624390
- 先挖好坑,明天该去郑轻找虐
- RMQ(Range Minimum/Maximum Query)问题是求区间最值问题。你当然可以写个O(n)的(怎么写都可以吧=_=),但是万一要询问最值1000000遍,估计你就要挂了。这时候你可以放心地写一个线段树(前提是不写错)应该不会挂。但是,这里有更简单的算法,就是ST算法,它可以做到O(nlogn)的预处理,O(1)地回答每个询问。
- 来看一下ST算法是怎么实现的(以最大值为例)
- 首先是预处理,用一个DP解决。设a[i]是要求区间最值的数列,f[i,j]表示从第i个数起连续2^j个数中的最大值。例如数列3 2 4 5 6 8 1 2 9 7 ,f[1,0]表示第1个数起,长度为2^0=1的最大值,其实就是3这个数。f[1,2]=5,f[1,3]=8,f[2,0]=2,f[2,1]=4……从这里可以看出f[i,0]其实就等于a[i]。这样,Dp的状态、初值都已经有了,剩下的就是状态转移方程。我们把f[i,j]平均分成两段(因为f[i,j]一定是偶数个数字),从i到i+2^(j-1)-1为一段,i+2^(j-1)到i+2^j-1为一段(长度都为2^(j-1))。用上例说明,当i=1,j=3时就是3,2,4,5 和 6,8,1,2这两段。f[i,j]就是这两段的最大值中的最大值。于是我们得到了动规方程F[i,j]=max(F[i,j-1],F[i+2^(j-i),j-1]).
【实现代码】
/*
pku3264
大意是给你一串数字,然后问你从第i个到第j个中最大的数减去最小的数的值
用rmq求出【i,j】中的最大最小值相减即可
rmq算法思想:
一,预处理
设a[i]是要求区间最值的数列,f[i,j]表示从第i个数起连续2^j个数中的最大值。
例如数列3 2 4 5 6 8 1 2 9 7 ,f[1,0]表示第1个数起,长度为2^0=1的最大值,其实就是3这个数。
f[1,2]=5,f[1,3]=8,f[2,0]=2,f[2,1]=4……从这里可以看出f[i,0]其实就等于a[i]。
这样,Dp的状态、初值都已经有了,剩下的就是状态转移方程。
我们把f[i,j]平均分成两段(因为f[i,j] 一定是偶数个数字),
从i到i+2^(j-1)-1为一段,i+2^(j-1)到i+2^j-1为一段(长度都为2^(j-1))。
用上例说明,当 i=1,j=3时就是3,2,4,5 和 6,8,1,2这两段。
f[i,j]就是这两段的最大值中的最大值。
于是我们得到了动规方程F[i,j]=max(F[i,j-1],F[i+2^(j-i),j-1]).
二,查询
如在上例中我们要求区间[2,8]的最大值,就要把它分成[2,5]和[5,8]两个区间,因为这两个区间的最大值我们可以直接由f[2,2]和f[5,2]得到。扩展到一般情况,就是把区间[l,r]分成两个长度为2^k的区间(保证有f[i,j]对应)。直接给出表达式:
k:=trunc(ln(r-l+1)/ln(2));
ans:=max(F[l,k],F[r-2^k+1,k]);
*/
#include <iostream>
#include <math.h>
#define max(a,b) ((a>b)?a:b)
#define min(a,b) (a<b?a:b) using namespace std; const int maxn=;
int h[maxn];
int mx[maxn][],mn[maxn][];
int n,q; void rmq_init()
{
int i,j,t;
for(j=;j<=n;j++) mx[j][]=mn[j][]=h[j];
int m=floor(log((double)n)/log(2.0));
for(i=;i<=m;i++){
for(j=;j<=n;j++){
t = j+(<<(i-));
if(t<=n) mx[j][i]=max(mx[j][i-],mx[t][i-]);
else mx[j][i]=mx[j][i-];
}
}
for(i=;i<=m;i++){
for(j=;j<=n;j++){
t = j+(<<(i-));
if(t<=n) mn[j][i]=min(mn[j][i-],mn[t][i-]);
else mn[j][i]=mn[j][i-];
}
}
} int rmq(int l,int r)
{
int m=floor(log((double)(r-l+))/log(2.0));
int a=max(mx[l][m],mx[r-(<<m)+][m]);
int b=min(mn[l][m],mn[r-(<<m)+][m]);
return a-b;
} int main()
{
int i,l,r;
scanf("%d%d",&n,&q);
for(i=;i<=n;i++) scanf("%d",&h[i]);
rmq_init();
for(i=;i<q;i++){
scanf("%d%d",&l,&r);
printf("%d\n",rmq(l,r));
}
return ;
}
【题目链接:NYOJ-1185】
最大最小值
-
给出N个整数,执行M次询问。对于每次询问,首先输入三个整数C、L、R:
如果C等于1,输出第L个数到第R个数之间的最小值;
如果C等于2,输出第L个数到第R个数之间的最大值;
如果C等于3,输出第L个数到第R个数之间的最小值与最大值的和。
(包括第L个数和第R个数)。
- 输入
- 首先输入一个整数T(T≤100),表示有T组数据。
对于每组数据,先输入一个整数N(1≤N≤10000),表示有N个整数;
接下来一行有N个整数a(1≤a≤10000);
然后输入一个整数M,表示有M次询问;
接下来有M行(1≤M≤10000),每行有3个整数C、L、R(1≤C≤3,1≤L≤R≤N)。 - 输出
- 按照题意描述输出。每个输出占一行。
- 样例输入
-
2
4
1 3 2 4
2
1 1 4
2 2 3
5
1 2 3 4 5
1
3 1 5 - 样例输出
-
1
3
6 -
#include <cstdio>
#include <math.h>
#define max(a,b) ((a>b)?a:b)
#define min(a,b) (a<b?a:b) const int maxn=;
int h[maxn];
int mx[maxn][],mn[maxn][];
int n,q; void rmq_init()
{
int i,j,t;
for(j=;j<=n;j++) mx[j][]=mn[j][]=h[j];
int m=floor(log((double)n)/log(2.0));
for(i=;i<=m;i++){
for(j=;j<=n;j++){
t = j+(<<(i-));
if(t<=n) mx[j][i]=max(mx[j][i-],mx[t][i-]);
else mx[j][i]=mx[j][i-];
}
}
for(i=;i<=m;i++){
for(j=;j<=n;j++){
t = j+(<<(i-));
if(t<=n) mn[j][i]=min(mn[j][i-],mn[t][i-]);
else mn[j][i]=mn[j][i-];
}
}
}
int rmq(int l,int r)
{
int m=floor(log((double)(r-l+))/log(2.0));
int a=max(mx[l][m],mx[r-(<<m)+][m]);
int b=min(mn[l][m],mn[r-(<<m)+][m]);
return a+b;
}
int out_min(int l,int r){
int m=floor(log((double)(r-l+))/log(2.0));
int b=min(mn[l][m],mn[r-(<<m)+][m]);
return b;
}
int out_max(int l,int r){
int m=floor(log((double)(r-l+))/log(2.0));
int a=max(mx[l][m],mx[r-(<<m)+][m]);
return a;
}
int main()
{
int i,l,r;
int T,C,L,R;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
for(i=;i<=n;i++) scanf("%d",&h[i]);
rmq_init();
scanf("%d",&q);
while(q--){
scanf("%d%d%d",&C,&L,&R);
if(C == )
printf("%d\n",out_min(L,R));
else if(C == )
printf("%d\n",out_max(L,R));
else if(C == )
printf("%d\n",rmq(L,R));
}
}
return ;
}
【RMQ问题】求数组区间最大值,NYOJ-1185-最大最小值的更多相关文章
- js求数组的最大值--奇技淫巧和笨方法
写这篇文章的原因 我目前做的项目很少用到算法,于是这方面的东西自然就有点儿生疏.最近的一次编码中遇到了从数组中获取最大值的需求,当时我不自觉的想到了js的sort()函数,现在想来真是有些“罪过”,当 ...
- c# 求数组的最大值
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- YTU 2642: 填空题:类模板---求数组的最大值
2642: 填空题:类模板---求数组的最大值 时间限制: 1 Sec 内存限制: 128 MB 提交: 646 解决: 446 题目描述 类模板---求数组的最大值 找出一个数组中的元 ...
- 使用JavaScript·求数组的最大值和最小值
前言 在数组中并没有提供arr.max()和arr.min()这样的方法.那么是不是可以通过别的方式实现类似这样的方法呢?那么今天我们就来整理取出数组中最大值和最小值的一些方法. 法一:其实利用 ...
- nyoj 1185 最大最小值【线段树最大值最小值维护】
最大最小值 时间限制:1000 ms | 内存限制:65535 KB 难度:2 描述 给出N个整数,执行M次询问. 对于每次询问,首先输入三个整数C.L.R: 如果C等于1,输出第L个数到第R ...
- java二维数组求每行最大值,每列最小值,及输出数组主对角线上的元素
总结:完全搞不懂,行和列是怎么弄的,,,,, package com.c2; import java.util.Scanner; public class Oaa { public static vo ...
- C#中求数组的子数组之和的最大值
<编程之美>183页,问题2.14——求子数组的字数组之和的最大值.(整数数组) 我开始以为可以从数组中随意抽调元素组成子数组,于是就有了一种想法,把最大的元素抽出来,判断是大于0还是小于 ...
- 求数组的最小数、最大值,求一组数的平均数,sort函数详解,类数组转数组
求数组的最小值和最大值 //求数组当中最大值和最小值 var arr=[3,2,6,1,45,23,456,23,2,6,3,45,37,89,30]; //第一种方法 根据排序方法来求最大值和最小值 ...
- JAVA 求数组中的最大值
package Code411;//求数组的最大值public class CodeArrayMax { public static void main(String[] args) { int ar ...
随机推荐
- PHP之SQL防注入代码(360提供)
<?php class sqlsafe { private $getfilter = "'|(and|or)\\b.+?(>|<|=|in|like)|\\/\\*.+?\ ...
- javax.mail.MessagingException: 501 Syntax: HELO hostname Linux端异常解决
在项目里面使用javamail在window环境正常,放在服务器上面的时候抛出异常javax.mail.MessagingException: 501 Syntax: HELO hostname ,原 ...
- Eclipse Error: Unable to set localhost. This prevents creation of a GUID.
Symptoms The following error appears in the atlassian-confluence.log: 2011-03-16 18:20:03,021 ERROR ...
- 理解lua 语言中的点、冒号与self
转载自: http://blog.csdn.net/wangbin_jxust/article/details/12170233 lua编程中,经常遇到函数的定义和调用,有时候用点号调用,有时候用冒号 ...
- poj 3625 Building Roads(最小生成树,二维坐标,基础)
题目 //最小生成树,只是变成二维的了 #define _CRT_SECURE_NO_WARNINGS #include<stdlib.h> #include<stdio.h> ...
- 解决maven-dependency-plugin (goals "copy-dependencies", "unpack") is not supported by m2e.错误
POM文件报错maven-dependency-plugin (goals "copy-dependencies", "unpack") is not supp ...
- hdu1102
http://acm.hdu.edu.cn/showproblem.php?pid=1102 最小生成树(模板题) 3 0 990 692 990 0 179 692 179 0 1 1 2 一共3个 ...
- 使用ajax()方法加载服务器数据
使用ajax()方法加载服务器数据 使用ajax()方法是最底层.功能最强大的请求服务器数据的方法,它不仅可以获取服务器返回的数据,还能向服务器发送请求并传递数值,它的调用格式如下: jQuery.a ...
- SaaS系列介绍之十二: SaaS产品的研发模式
1 产品研发模式慨述 产品研发模式是企业战略的重点.产品研发路线决定了一系列的管理手段和团队建设问题.也是企业的整理策略和经营思路.产品研发模式贯穿着整个产品的生命周期,从市场调研.立项.需求分析.慨 ...
- springmvc常用注解之@Controller和@RequestMapping
对于各种注解而言,排第一的当然是“@Controller”,表明某类是一个controller. “@RequestMapping”请求路径映射,如果标注在某个controller的类级别上,则表明访 ...