一、前言

RMQ问题、即区间最值问题,在遇到这类题目的时候,我们可以用暴力枚举两重for循环的方式来解决,但是这样的话会在时间上超时。如果想要不超时的话,我们也可以用线段树来解决该问题。但是我们在日常的训练中意识到:线段树的代码比较多并且比较复杂,稍有不慎的话就有可能出错。因此,在这里作者简单介绍一种写起来比较简单的算法-----ST算法。

例题引入:Acwing 天才的记忆

从前有个人名叫 WNB,他有着天才般的记忆力,他珍藏了许多许多的宝藏。在他离世之后留给后人一个难题(专门考验记忆力的啊!),如果谁能轻松回答出这个问题,便可以继承他的宝藏。题目是这样的:给你一大串数字(编号为 1到 N,大小可不一定哦!),在你看过一遍之后,它便消失在你面前,随后问题就出现了,给你 M 个询问,每次询问就给你两个数字 A,B,要求你瞬间就说出属于 A 到 B这段区间内的最大数。一天,一位美丽的姐姐从天上飞过,看到这个问题,感到很有意思(主要是据说那个宝藏里面藏着一种美容水,喝了可以让这美丽的姐姐更加迷人),于是她就竭尽全力想解决这个问题。但是,她每次都以失败告终,因为这数字的个数是在太多了!于是她请天才的你帮他解决。如果你帮她解决了这个问题,可是会得到很多甜头的哦!
输入格式第一行一个整数 N表示数字的个数。接下来一行为 N个数,表示数字序列。第三行读入一个 M,表示你看完那串数后需要被提问的次数。接下来 M行,每行都有两个整数 A,B。
输出格式输出共 M行,每行输出一个数,表示对一个问题的回答。
数据范围1≤N≤2×105
,
1≤M≤104,
1≤A≤B≤N。
输入样例:6
34 1 8 123 3 2
4
1 2
1 5
3 4
2 3输出样例:34
123
123
8

二、算法介绍

首先定义dp[i,j]为以第i个数为起点,长度为2j的一段区间中的最大值,显然状态转移为

dp[i,j] = max(dp[i,j-1],dp[i+2(j-1),j-1])

这样的话可以在nlogn的时间下完成f数组的建立,下边是区间最大值的查询,对于区间[l,r],存在一个k使得r-l+1>=2k且r-l+1<2(k+1),这样的话区间[l,r]的最大值就是max(dp[l,k],dp[r-2k+1,k]),查询可以在常数级完成。
在这里可以用这张图解释一下状态转移方程的推导逻辑。

三、代码实现

1.ST算法
// Problem: 天才的记忆
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/1275/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)//#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
#define INF 0x3f3f3f3f
#define ull unsigned long long
#define mem(a, b) memset(a, b, sizeof(a))
#define ck(x) cerr << #x << "=" << x << '\n';
using namespace std;
typedef pair<int, int> PII;
const int N = 1e6 + 7, mod = 1e9 + 7;
int dp[N][20];
int a[N];void solve()
{int n;cin >> n;for (int i = 1; i <= n; i++)cin >> a[i];int q;for (int j = 0; j < 18; j++){for (int i = 1; i + (1 << j) - 1 <= n; i++)if (!j)dp[i][j] = a[i];elsedp[i][j] = max(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]);}cin >> q;while (q--){int l, r;cin >> l >> r;int k = r - l + 1;k = log(k) / log(2);int ans = max(dp[l][k], dp[r - (1 << k) + 1][k]);cout << ans << endl;}
}signed main()
{std::ios::sync_with_stdio(false);cin.tie(0), cout.tie(0);solve();return 0;
}
2.线段树
//#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
#define INF 0x3f3f3f3f
#define ull unsigned long long
#define mem(a, b) memset(a, b, sizeof(a))
#define ck(x) cerr << #x << "=" << x << '\n';
using namespace std;
typedef pair<int, int> PII;
const int N = 1e6 + 7, mod = 1e9 + 7;
int a[N];
struct Node
{int l, r, v;
} tr[N * 4];
void pushup(int u)
{tr[u].v = max(tr[u << 1].v, tr[u << 1 | 1].v);
}
void build(int u, int le, int ri)
{if (le == ri)tr[u] = { le, ri, a[le] };else{tr[u] = { le, ri };int mid = (le + ri) >> 1;build(u << 1, le, mid);build(u << 1 | 1, mid + 1, ri);pushup(u);}
}
int query(int u, int le, int ri)
{if (tr[u].l >= le && tr[u].r <= ri)return tr[u].v;else{int mid = (tr[u].l + tr[u].r) >> 1;int ans = -INF;if (le <= mid)ans = max(ans, query(u << 1, le, ri));if (mid < ri)ans = max(ans, query(u << 1 | 1, le, ri));return ans;}
}
void solve()
{int n;cin >> n;for (int i = 1; i <= n; i++)cin >> a[i];int q;build(1, 1, n);cin >> q;while (q--){int l, r;cin >> l >> r;cout << query(1, l, r) << endl;;}
}signed main()
{std::ios::sync_with_stdio(false);cin.tie(0), cout.tie(0);solve();return 0;
}

作者:Avalon Demerzel

【动态规划】ST算法解决区间最值询问问题(RMQ问题)相关推荐

  1. RMQ的ST算法(区间最值)

    ST算法求解RMQ问题(区间最值) 效率:O(n log n)预处理,O(1)询问 思想: 用 f [ i ][ j ] 表示 以i 开头的区间,包括2^j 个元素的一段区间的最值 那么有初始化的初始 ...

  2. st算法 求区间最值问题

    算法的一个实现方法如下. 其中使用位运算替代2的幂次的计算,加快运算速度. 使用时需要先调用initRMQ()进行初始化,然后再调用RMQ(u,v)进行查询. 1 const int mx = 100 ...

  3. ST算法解决RMQ问题

    关于ST算法,实际上它本身并不难,它的思想是动态规划.主要用来求RMQ问题,时间复杂度为O(NlgN+M)  关于RMQ问题描述: 输入N个数和M次询问,每次询问一个区间[L,R],求第L个数到R个数 ...

  4. java开发模拟退火算法解决函数最值!

    在众多搜索算法之中,模拟退火是一种搜索性的算法,但是它的缺点在于收敛性比较弱. 这里主要运用模拟退火算法解决函数y=xsin(10xpi)+2的最优值问题. 代码及算法原理如下: /********* ...

  5. 疯子的算法总结14--ST算法(区间最值)

    借助倍增和动态规划可以实现O(1)的时间复杂度的查询 预处理: ①区间DP   转移方程  f[i][j] = min(MAX同理)(f[i][j - 1],f[i + ][j - 1])  f[i] ...

  6. ST算法 - RMQ(区间最值问题)—— 倍增

    文章目录 引入倍增: 例题1:区间和 例题2:Genius ACM 应用: ST算法 求解 RMQ(区间最值问题) 模板Code: 练习题: ST算法 维护区间最大公约数 例题:Pair of Num ...

  7. RMQ(求区间最值问题)

    学习博客:https://blog.csdn.net/qq_31759205/article/details/75008659 RMQ(Range Minimum/Maximum Query),即区间 ...

  8. RMQ ST算法简介

    RMQ (Range Minimum/Maximum Query)问题是指:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中下标在i,j里的最小(大)值,也就 ...

  9. 数据结构:线段树及ST算法比较

    ST算法是一种高效的计算区间最值的方法. 他的思想是将询问区间分解成两个最长的二次幂的长度的区间并集的形式. 所以与线段树不同,这种区间分解其实存在相交的分解. 因此ST算法能维护的只是一些简单的信息 ...

  10. CodeForces 359D (数论+二分+ST算法)

    题目链接: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=47319 题目大意:给定一个序列,要求确定一个子序列,①使得该子序 ...

最新文章

  1. kafka启动异常:kafka.common.InconsistentClusterIdException: The Cluster ID xxx
  2. createprocess 系统找不到指定的文件_windows找不到gpedit.msc请确定文件名
  3. Hbase Compaction 源码分析 - RatioBasedCompactionPolicy 策略
  4. 人工智能ai知识_人工智能中基于知识的代理层
  5. [Winodows Phone 7控件详解]Silverlight toolkit for Windows Phone 7.1控件-5
  6. 蓝桥杯 ADV-165算法提高 超级玛丽(动态规划、递推)
  7. 给力者基于51单片机的C语言教程,给力者单片机开发教程
  8. java poi 水印_poi excel如何设置水印透明度
  9. 关服了的手游怎么进去_关服手游改成单机教程
  10. 基因组测序数据分析linux,基因组重测序数据分析脚本
  11. matlab三次样条插值代码
  12. 【论文阅读|深读】RolNE: Improving the Quality of Network Embedding with Structural Role Proximity
  13. 微信公众号页面如何跳转至关注公众号页面
  14. 双模控制器很耗电_双模电动车控制器主要功能
  15. 【每日快讯】2018年5月12日 [星期六]
  16. 夜深了 是时候爬个小黄图了
  17. C# dataGridView 序号自动递增
  18. 史上最全软件测试工程师常见的面试题总结(百度、oppo、中软国际、华为)备战金三银四
  19. Qt入门教程【高级控件篇】QListWidget列表小部件
  20. 手机上的android版本下载视频播放器,ZZPlayer手机版下载

热门文章

  1. MySQL 索引分析
  2. Linux中使用Apache发布html网页
  3. 8253/8255/8259相关知识
  4. 用c#开发微信 (4) 基于Senparc.Weixin框架的接收事件推送处理 (源码下载)
  5. 计算机操作系统笔记——线程及其实现
  6. 查看系统信息msinfo32工具的使用
  7. 【BZOJ】3963: [WF2011]MachineWorks
  8. GNS3中RIP的过滤和修改
  9. New Concept English Two 5
  10. 在安卓中对应用进行单元测试