RMQ - ST表

news2024/11/18 11:48:32

RMQ - ST表

1、RMQ 简介

  • RMQ (Range Minimum / Maximum Query) 问题是指:对于长度为 n n n 的数列 A A A,回答若干询问 ( A , i , j ) (A, i, j) (A,i,j) ( 1 ≤ i , j ≤ n ) (1≤i,j≤n) (1i,jn),返回数列 A 中区间在 [ i , j ] [i,j] [i,j] 中的最小 (大) 值所在的下标。也就是说, R M Q RMQ RMQ 问题是指求区间最值的问题。
  • R M Q RMQ RMQ 总体来说还是动态规划的思想,相对比较独立的算法,不需要太深的程序和算法基础,而且相对好理解!

个人理解

  • 解决区间 上简单的静态问题

朴素 RMQ

  • 以区间最小值为例,对于区间 [ l , r ] [l, r] [l,r],从第 l l l 个元素枚举到第 r r r 个元素,将值最小的元素的下标存储在变量 i d x idx idx 上,一旦遇到比记录的元素小的就更新 i d x idx idx 的值,枚举完所有 r − l + 1 r-l+1 rl+1 个元素后,得到最小值所在的下标。

    int QueryMinIndex(int l, int r) {
        int idx = l;
        for(int i = l + 1; i <= r; ++i) {
            if(A[i] < A[idx]) {
                idx = i;
            }
        }
        return idx;
    }
    
  • 我们发现这个算法的时间复杂度,最坏情况下就是 l = 1 , r = n l = 1,r = n l=1r=n 的情况,为 O ( n ) O(n) O(n)

  • 当询问比较频繁的时候,这个算法的时间复杂度是无法满足要求的。

RMQ - ST 算法

  • S T ( S p a r s e T a b l e ) ST(Sparse Table) STSparseTable算法是基于动态规划的,之前在说到动态规划的时候,有个很重要的概念就是状态。
  • 求解区间最大值可以通过所有数字增加一个负号转化成求区间最小值问题,所以这里我们可以只讨论区间最小值问题。
  • 这个算法也利用到了状态的概念,用 f[i][j] 表示起点为 j j j,长度为 2 i 2^i 2i 的区间内的最大值所在下标。通俗的讲,f[i][j]f[i][j] 就是区间 [ j , j + 2 i ) [j, j + 2^i) [j,j+2i) 内的最大值的下标(注意:这里表示的区间为左闭右开)。

对于长度为 16 16 16 的数组, f [ i ] [ j ] f[i][j] f[i][j] 所表示的区间如下:

在这里插入图片描述

  • 由于区间 [ j , j + 2 i ) [j, j + 2^i) [j,j+2i) 长度为 2 i 2^i 2i,如果 i > 0 i > 0 i>0,那么它可以分解成两个长度为 2 i − 1 2^{i-1} 2i1 的区间,即:
    [ j , j + 2 i ) = [ j , j + 2 i − 1 ) + [ j + 2 i − 1 , j + 2 i ) [j, j + 2^i) = [j, j + 2^{i-1}) + [j + 2^{i-1}, j + 2^i) [j,j+2i)=[j,j+2i1)+[j+2i1,j+2i)
  • i = 3 , j = 4 i=3, j = 4 i=3,j=4 时,有 [ 4 , 12 ) = [ 4 , 8 ) + [ 8 , 12 ) [4, 12) = [4,8) + [8,12) [4,12)=[4,8)+[8,12),更加直观的

在这里插入图片描述

int RMQ_MinIndex(ValueType A[], int l, int r) {
    return A[r] < A[l] ? r : l;
}
  • 这个函数在传参时需要保证 l ≤ r l \le r lr,并且由于数组长度并不一定是 2 的幂,所以 r r r 有可能超出数组长度,所以调用方需要进行边界判断;
  • 通过这个函数,可以得到 f [ i ] [ j ] f[i][j] f[i][j] 的状态转移方程如下:

在这里插入图片描述

  • 其中 o p t opt opt 就是RMQ_MinIndex函数;

ST表实际上就是DP

注:

个人习惯不同, i , j i,j i,j 表示的意义不同(下面与上面正好相反),根据个人习惯进行code就行

预处理 ST表

for (int i = 1; i <= n; i++)
        st[i][0] = s[i];

    for (int i = 1; i <= 20; i++)
        for (int j = 1; j + (1 << i) - 1 <= n; j++)
            st[j][i] = max(st[j][i - 1], st[j + (1 << (i - 1))][i - 1]);
  • f [ i ] [ j ] f[i][j] f[i][j] 的状态数目有多少呢?
  • 由于 i < = l o g ( n ) , j < = n i <= log(n),j<=n i<=log(n),j<=n,所以总的状态数为 n l o g ( n ) nlog(n) nlog(n),每次状态转移的时间复杂度为 O(1),所以预处理总时间为 O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n))

询问

  • f [ i ] [ j ] f[i][j] f[i][j] 的计算只是做了一步预处理,但是我们在询问的时候,不能保证每个询问区间长度都是 2 2 2 的幂,如何利用预处理出来的值计算任何长度区间的值就是我们接下来要解决的问题。

  • 区间长度等于 1 1 1 的情况最小值就等于它本身;

  • 区间长度大于 1 1 1 时,即给定任意区间 [ a , b ] ( 1 ≤ a < b ≤ n ) [a, b] (1 \le a < b \le n) [a,b](1a<bn),必定可以找到两个区间 X X X Y Y Y,它们的并是 [ a , b ] [a, b] [a,b],并且区间 X X X 的左端点是 a a a,区间 Y Y Y 的右端点是 b b b,而且两个区间长度相等,且都是 2 的幂。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iOPhE0PK-1671893490468)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20221224182929924.png)]

  • 设区间长度为 2 k 2^k 2k,则 X X X 表示的区间为 [ a , a + 2 k ) [a, a + 2^k) [a,a+2k) Y Y Y 表示的区间为 ( b − 2 k , b ] (b - 2^k, b] (b2k,b],则需要满足一个条件就是 X X X 的右端点必须大于等于 Y Y Y 的左端点减一,即 a + 2 k − 1 ≤ b − 2 k a+2^k-1 \le b-2^k a+2k1b2k,通过移项得到:

  • 2 k + 1 ≥ ( b − a + 1 ) 2^{k+1} \ge (b-a+1) 2k+1(ba+1)

  • 两边取对数(以2为底),得 k + 1 ≥ l o g 2 ( b − a + 1 ) k+1 \ge log_2(b-a+1) k+1log2(ba+1),最后得到:

    k ≥ l o g 2 ( b − a + 1 ) − 1 k \ge log_2(b-a+1) - 1 klog2(ba+1)1

  • 所以这里, k k k 只要需要取最小的满足条件的整数即可, b − a + 1 b-a+1 ba+1 的取值为 [ 2 , n ] [2, n] [2,n],可以通过预处理把所有 k k k 求出来。

  • l o g 2 v log_2v log2v 为整数时, k = l o g 2 v − 1 k = log_2v - 1 k=log2v1;否则 k k k l o g 2 v − 1 log_2v - 1 log2v1 的上整。

int query(int l, int r)
{
    int renk = log2(r - l + 1);

    return max(st[l][renk], st[r - (1 << renk) + 1][renk]);
}

板子

#include <bits/stdc++.h>
#define buff                     \
    ios::sync_with_stdio(false); \
    cin.tie(0);
//#define int long long
using namespace std;
const int N = 100010;
int st[N][21];
int s[N];
int n, q;

int query(int l, int r)
{
    int renk = log2(r - l + 1);

    return max(st[l][renk], st[r - (1 << renk) + 1][renk]);
}

void solve()
{
    cin >> n >> q;
    for (int i = 1; i <= n; i++)
        cin >> s[i];

    for (int i = 1; i <= n; i++)
        st[i][0] = s[i];

    for (int i = 1; i <= 20; i++)
        for (int j = 1; j + (1 << i) - 1 <= n; j++)
            st[j][i] = max(st[j][i - 1], st[j + (1 << (i - 1))][i - 1]);
    while (q--)
    {
        int l, r;
        cin >> l >> r;
        cout << query(l, r) << '\n';
    }
    
}
int main()
{
    buff;
    solve();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/112931.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue2.0全面教程

Vue2.0 学习视频地址 文章目录Vue2.01.vue 简介1.1.什么是vue1.2.vue的两个特性1.2.1.数据驱动视图1.2.2.双向数据绑定1.3.MVVM概述1.4.MVVM工作原理2.vue的基本使用2.1.基本使用步骤2.2.基本代码与MVVM的对应关系3.vue的调试工具3.1.安装vue-devtool调试工具3.2.配置Chrome浏…

Axios(三)

目录 1.Axios的默认配置 2.Axios创建Ajax实例对象发送请求 3.Axios拦截器 4.Axios取消请求 5.Axios文件结构说明 6.Axios创建过程 7.Axios对象创建过程模拟实现 8.Axios发送请求过程详解 9.模拟实现Axios发送请求 1.Axios的默认配置 <!doctype html> <html …

QT系列第7节 标准对话框使用

QT编程中对话框作为最常用的窗口经常被使用&#xff0c;本节介绍一些QT常用的标准对话框使用。 目录 1.选择单文件 2.选择多文件 3.选择目录 4.文件存储 5.选择颜色 6.选择字体 7.输入字符换/整数/浮点数/条目 8.消息对话框 9.进度对话框 10.向导对话框 1.选择单文件…

【圣诞节限定】今天教你如何用Html+JS+CSS绘制3D动画圣诞树

一、前言 应CSDN的邀请&#xff0c;这次给大家展示一波&#xff0c;如何用H5技术绘制3D圣诞树。 二、创意名 只采用简单的HtmlJSCSS 技术绘制。 三、效果展示 圣诞树修过如下&#xff1a; 四、编码实现 将源码复制保存到html中打开即可。 <!DOCTYPE html> <html lang…

ChatGPT与BimAnt的1小时对话实录【数字孪生】

本文为BimAnt和ChatGPT对数字孪生相关问题的解答&#xff0c;感觉这个AI真的已经“懂”了很多东西&#xff0c;让人恍惚间忘了是在和bot对话。 BimAnt&#xff1a;hello ChatGPT&#xff1a;Hello! How can I help you today? BimAnt&#xff1a;can you speak chinese&am…

鲸鱼优化算法及其在无线网络资源分配中的应用(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 鲸鱼优化算法&#xff08;Whale Optimization Algorithm&#xff09;是一种新兴的智能优化算法&#xff0c;在2016年提出。算法…

JWT渗透与攻防(二)

目录 前言 JWT漏洞演示之CTFhub&#xff08;一&#xff09; JWT漏洞演示之CTFhub&#xff08;二&#xff09; 前言 我们在之前的文章中已经讲解过了JWT漏洞相关的原理和利用&#xff0c;今天我们就通过这篇文章再来了解一下JWT的漏洞。 JWT漏洞演示之CTFhub&#xff08;一&…

Linux-信号

文章目录信号准备知识&#xff1a;信号产生的方式实验验证&#xff1a;9号信号是不可被捕捉&#xff08;自定义的&#xff09;信号处理&#xff1a;信号产生前&#xff1a;信号产生的方式&#xff1a;键盘实验显示&#xff1a;段错误&#xff08;野指针&#xff09;实验验证&am…

SSRF ME XCTF

题目 就是一个验证框和URL框&#xff0c;两个都必须有参数 解法 验证码 做一个粗略的脚本&#xff0c;一般验证码都是数字&#xff0c;所以直接开md5&#xff1a; def cmpcapt(substr):for i in range(1,100001):md5 hashlib.md5(str(i).encode(utf-8))hexmd5 md5.hexd…

机器学习任务功略

目录 机器学习的结构机器学习攻略 训练集loss较大 model bias问题optimization问题 gradient descent的问题解决 如何区分训练集loss大是model bias还是优化器的问题 测试集loss较大 overfitting过拟合 为什么会有overfitting解决过拟合的方法 训练集与测试集的不匹配 如何选择…

Linux内核基础篇——常用调试技巧汇总

文章目录printk动态输出BUG()和BUG_ON()dump_stack()devmemprintk printk共有8个等级&#xff0c;从0-7&#xff0c;等级依次降低。 打印等级可以通过修改/proc/sys/kernel/printk来改变。 查看printk等级&#xff1a; cat /proc/sys/kernel/printk 7 4 1 7打开内核所有打印…

2022圣诞树(C语言摇钱树版本)

逐梦编程&#xff0c;让中华屹立世界之巅。 简单的事情重复做,重复的事情用心做,用心的事情坚持做&#xff1b; 文章目录前言一、个人感悟二、圣诞树由来三、圣诞树发展历史演变四、常见的圣诞树种类五、摇钱圣诞树效果展示六、实现思路七、编码实现总结新壁纸前言 时光飞逝&a…

前端工程师必须掌握—《Webpack教程》

Webpack 学习视频地址 文章目录Webpack1.webpack基础1.1.初始化隔行变色的案例1.2.安装和配置webpack1.2.1.安装webpack1.2.2.配置webpack1.2.3.了解mode可选值的应用场景1.2.4.自定义打包的入口和出口2.插件2.1.安装和配置webpack-dev-server2.1.1.安装webpack-dev-server2.1…

SpringCache+Redis的整合(微服务)

缓存作用&#xff1a; 举个例子&#xff1a;在我们程序中&#xff0c;很多配置数据&#xff08;例如一个商品信息、一个白名单、一个第三方客户的回调接口&#xff09;&#xff0c;这些数据存在我们的DB上&#xff0c;数据量比较少&#xff0c;但是程序访问很频繁&#xff0c;…

Prometheus(十一)Grafana告警

主要概念和特点 关键概念或特征含义Data sources for Alerting 告警的数据源配置从哪里查询到告警信息数据Provisioning for Alerting 告警的配置使用文件等方式配置警报资源&#xff0c;已经管理警报资源Scheduler 调度器评估告警规则&#xff0c;将其视为定期对数据源运行查…

ubuntu虚拟机修改静态ip

我的是&#xff1a;ubuntu 20.04&#xff0c;所以 第一步 sudo vi /etc/netplan/01-network-manager-all.yaml第二步 gateway4已经弃用了&#xff0c;换成下面的&#xff1a; network:version: 2renderer: NetworkManagerethernets:ens33:addresses: [192.168.125.132/24]r…

内核比较: 2.6 内核中改进了内存管理

随着 Linux 内核的发展和成熟&#xff0c;更多的用户期待着 Linux 可以运行非常大的系统来处理科学分析应用程序或者海量数据库。这些企业级的应用程序通常需要大量的内存才能好好运行。2.4 Linux 内核有识别相当大数量的内存的功能&#xff0c;但是 2.5 内核发生了很多改变&am…

docker高级篇第三章-dockerfile案例之制作自己的centos镜像

在上一篇文章中《Dockerfile介绍及常用保留指令》,我们介绍了Dockerfile是什么以及Dockerfile常用的保留字段。熟悉了这些之后,有没有想自己动手写一个Dockerfile呢?本文咱们就实战自己Dockerfile。 案例需求: 我们以远程仓库的centos为模板,制作出代用vim\ifconfig\jav…

Qt实现表格树控件-自绘树节点虚线

一、开心一刻 一程序员第一次上女朋友家她妈板着脸问 &#xff1a;你想娶我女儿&#xff0c;有多少存款&#xff1f; 程序员低了下头&#xff1a;五百&#xff01; 她妈更鄙视了&#xff1a;才五百块&#xff0c;买个厕所都不够&#xff01; 程序员忙说&#xff1a;不是人民币&…

Android混淆技术综述

1. 引入 大量的恶意软件都使用了混淆技术来逃检测。查了下Android混淆技术&#xff0c;看了如下两篇资料&#xff1a; Understanding Android Obfuscation Techniques: A Large-Scale Investigation in the Wildhttps://github.com/ClaudiuGeorgiu/Obfuscapk 对Android的混淆…