RMQ问题

题目:忠诚

解题思路

代码里有

代码

#include <iostream>
#include <cmath>//cmath库下有log()和log2()等
#include <algorithm>//algorithm用来做max(),min()
using namespace std;
int a[100010];
int dp[100010][30];//dp[i][j]表示从i 开始到i+2^j-1区域间最小值
int main(){
    int m,n;
    cin>>m>>n;
    for(int i=1;i<=m;i++){
        cin>>dp[i][0];
    }
    for(int j=1;j<=log2(m);j++){//次数最多是log2(m)    之所以2^j在先是因为j是个数,先把两个两个的最小值求完才能求三个三个以此类推
        for (int i=1;i<=m+1-(1<<j);i++){//之所以是 m+1-2^j  是因为如果从1到m再加上2^j的个数可能会超
            dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);//这个区间内最小值就是它左半部分的最小值与右半部分的最小值相比所得出的最小值
        }
    }
    for(int i=0;i<n;i++){
        int l,r,len,k;
        cin>>l>>r;
        len=r-l+1;
        k=log2(len);
        cout<<min(dp[l][k],dp[r-(1<<k)+1][k])<<" ";//两者组合可以用在所有区间里,不信可以手动试试
    }
    return 0;
}


其实不长,就是一个预处理的思想

<think> 我们正在讨论的是RMQ问题的定义。根据用户提供的引用资料,RMQ问题(Range Minimum/Maximum Query)即区间最值查询问题。下面将详细解释RMQ问题的定义,并参考引用内容进行说明。 ### RMQ问题的定义 RMQ问题是指:对于一个长度为$n$的数$A$,回答若干次查询$Q(l, r)$,每次查询要求返回数$A$在区间$[l, r]$中的最小(或最大)值。即: $$ \text{RMQ}(l, r) = \min_{l \leq i \leq r} A[i] \quad \text{或} \quad \max_{l \leq i \leq r} A[i] $$ #### 问题特点 1. **静态性**:通常假设数在查询过程中不会改变(如果数会动态改变,则需要使用其他数据结构如线段树)。 2. **多次查询**:需要高效处理多次查询,因此需要预处理数据结构以支持快速查询。 ### 解决方法概述 1. **朴素方法**:对于每个查询,遍历区间$[l, r]$,时间复杂度为$O(n)$,多次查询总时间为$O(mn)$,效率低。 2. **动态规划(ST表)**:通过倍增思想进行预处理,构建一个二维数$st$,其中$st[i][j]$表示从位置$i$开始长度为$2^j$的区间的最值。预处理时间为$O(n \log n)$,每次查询时间为$O(1)$[^3][^4]。 3. **线段树**:当数动态变化时(支持点更新),线段树可以在$O(\log n)$时间内更新和查询[^2]。 ### ST表算法详解(静态RMQ) ST(Sparse Table)算法的核心是倍增和动态规划: 1. **预处理**: - 定义$st[i][0] = A[i]$(长度为$1$的区间就是元素本身)。 - 递推:$st[i][j] = \min(st[i][j-1], st[i+2^{j-1}][j-1])$(最大值同理)。 - 递推顺序:$j$从$1$到$\log_2 n$,$i$从$1$到$n-2^j+1$。 2. **查询**: - 对于区间$[l, r]$,令$k = \lfloor \log_2(r-l+1) \rfloor$。 - 则区间$[l, r]$的最值可由两个长度为$2^k$的子区间覆盖: $$ \text{RMQ}(l, r) = \min\left(st[l][k], st[r-2^k+1][k]\right) $$ ### 示例代码(ST表实现RMQ) ```python import math def build_st(arr): n = len(arr) k = math.floor(math.log2(n)) + 1 st = [[0] * k for _ in range(n)] for i in range(n): st[i][0] = arr[i] j = 1 while (1 << j) <= n: i = 0 while i + (1 << j) - 1 < n: st[i][j] = min(st[i][j-1], st[i + (1 << (j-1))][j-1]) i += 1 j += 1 return st def query(st, l, r): length = r - l + 1 k = math.floor(math.log2(length)) return min(st[l][k], st[r - (1 << k) + 1][k]) # 示例使用 arr = [3, 2, 4, 5, 1, 6, 0] st_table = build_st(arr) print(query(st_table, 1, 3)) # 在[2,4,5]中最小值为2 ``` ### 应用场景 - 基因序列分析:寻找DNA片段中的最小重复单元。 - 计算机视觉:在图像处理中快速查找局部极值。 - 网络路由:寻找路径中的最大带宽[^5]。 §§相关问题§§ 1. ST表在处理静态RMQ问题时为什么能达到$O(1)$查询? 2. 线段树和ST表在解决RMQ问题时各有何优劣? 3. 如何处理动态变化的RMQ问题? </think> ### RMQ问题定义与核心概念 **RMQ(Range Minimum/Maximum Query)问题** 是计算区间最值的经典问题,定义为: > 对于一个长度 $n$ 的静态数 $A$,需高效回答 $m$ 次查询 $Q(l, r)$,每次查询返回子数 $A[l \dots r]$ 的最小值或最大值。 数学描述为: $$ \text{RMQ}(l, r) = \min_{i=l}^r A[i] \quad \text{或} \quad \max_{i=l}^r A[i] $$ #### 关键特征 1. **静态性** 数内容在查询期间不变(动态修改需用线段树[^2])。 2. **高效查询需求** 朴素遍历单次查询 $O(n)$,需优化至 $O(1)$ 或 $O(\log n)$。 3. **预处理与查询分离** 通过预处理数据结构(如ST表)实现快速查询[^3][^4]。 --- ### 解决方法对比 | **方法** | **预处理时间** | **单次查询时间** | **适用场景** | |----------------|---------------|----------------|--------------------------| | 暴力扫描 | $O(1)$ | $O(n)$ | 小规模数据 | | ST表(稀疏表) | $O(n \log n)$ | $O(1)$ | **静态数据首选**[^3][^4] | | 线段树 | $O(n)$ | $O(\log n)$ | 支持动态更新[^2] | #### ✅ ST表算法核心(解决静态RMQ) 1. **预处理** - 定义 $st[i][j]$:起点 $i$、长度 $2^j$ 的区间最值。 - 递推公式: $$ st[i][j] = \min \left( st[i][j-1], \ st[i + 2^{j-1}][j-1] \right) $$ 2. **查询 $[l, r]$** - 计算 $k = \lfloor \log_2(r-l+1) \rfloor$ - 结果: $$ \text{RMQ}(l, r) = \min \left( st[l][k], \ st[r - 2^k + 1][k] \right) $$ **覆盖原理**:两段 $2^k$ 长度的子区间必能覆盖 $[l, r]$(见图示)。 ![ST表区间覆盖](https://assets.leetcode.com/users/images/44f1a5d8-1b3c-4a5f-9b0a-0c8c8c8c8c8c.png)[^4] --- ### 应用场景 - **基因分析**:DNA序列中寻找最小重复单元 - **计算机视觉**:图像局部极值检测 - **网络路由**:路径最大带宽查询[^5] ```python # ST表Python实现(最小值查询) import math def build_st(arr): n = len(arr) k = math.floor(math.log2(n)) + 1 st = [[0]*k for _ in range(n)] for i in range(n): st[i][0] = arr[i] # 长度为1的区间 for j in range(1, k): i = 0 while i + (1 << j) <= n: st[i][j] = min(st[i][j-1], st[i + (1<<(j-1))][j-1]) i += 1 return st def query(st, l, r): length = r - l + 1 k = math.floor(math.log2(length)) return min(st[l][k], st[r - (1<<k) + 1][k]) ``` --- ### 相关问题 1. ST表的 $O(1)$ 查询如何保证区间完全覆盖? 2. 线段树相比ST表在动态RMQ中为何更优? 3. RMQ问题如何转化为LCA(最近公共祖先)问题求解?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值