首页 > 其他分享 >数据结构——RMQ(ST表)问题

数据结构——RMQ(ST表)问题

时间:2024-07-07 15:19:27浏览次数:11  
标签:RMQ int mid 复杂度 cin ST 区间 mathcal 数据结构

数据结构——RMQ(ST表)问题

问题描述

对于序列 \(A[1\dots n]\),有 \(m\) 组询问 \(\langle l,r\rangle\),求 \(\max_{i=l}^rA_i\)。

我们下面使用 \(\mathcal O(A)\sim\mathcal O(B)\) 表示预处理 \(\mathcal O(A)\),单次询问 \(\mathcal O(B)\) 的时间复杂度。

线段树解法

时间复杂度:\(\mathcal O(n)\sim\mathcal O(\log n)\)。

空间复杂度:\(\mathcal O(n)\)。

#include <bits/stdc++.h>

using namespace std;

constexpr int N = 2e5 + 10;

int n, a[N];

#define ls(x) ((x) << 1)
#define rs(x) ((x) << 1 | 1)

int seg[N << 2];

void push_up(int k) {
    seg[k] = max(seg[ls(k)], seg[rs(k)]);
}

void build(int k = 1, int l = 1, int r = n) {
    if (l == r) return void(seg[k] = a[l]);
    int mid = l + r >> 1;
    build(ls(k), l, mid);
    build(rs(k), mid + 1, r);
    push_up(k);
}

int query(int p, int q, int k = 1, int l = 1, int r = n) {
    if (l >= p && r <= q) return seg[k];
    int mid = l + r >> 1;
    if (p > mid) return query(p, q, rs(k), mid + 1, r);
    if (q < mid + 1) return query(p, q, ls(k), l, mid);
    else return max(query(p, q, ls(k), l, mid), query(p, q, rs(k), mid + 1, r));
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);
    cin >> n;
    copy_n(istream_iterator<int>(cin), n, a + 1);
    build();
    int q, l, r; cin >> q;
    while (q--) cin >> l >> r, cout << query(l, r) << endl;
    return 0;
}

修改复杂度 \(\mathcal O(\log n)\)。

ST 表

ST 表可以做到 \(\mathcal O(n\log n)\) 预处理,\(\mathcal O(1)\) 求出序列区间最大值。

按照最基础的思想,设 \(f(i,j)\) 表示区间 \([i,j]\) 的最大值,考虑上述倍增思想。

重新设计状态,

用 \(f(i,j)\) 表示区间 \([i,i+2^j-1]\) 的最大值,也就是从 \(i\) 开始的 \(2^j\) 个数。

考虑这样子递推的边界,

  • 显然 \(f(i,0)=a_i\)。
  • 显然 \(f(i,j)=\max\{f(i,j-1),f(i+2^{j-1},j-1)\}\)。

这么折半的预处理,可以做到 \(\mathcal O(n\log n)\) 的复杂度。

考虑查询,如果我们按照朴素的思想去处理的话,也是 \(\mathcal O(n\log n)\) 的,但是

有一个很简单的性质,\(\max\{x,x\}=x\),这意味着我们可以重复计算一个区间的最大值。

于是,我们可以把区间中一部分重复的区间跳过,直接去计算:

能覆盖整个区间的两个左右端点上的整个区间,就可以做到 \(\mathcal O(1)\)。

除 RMQ 以外,还有其它的「可重复贡献问题」。例如「区间按位与」、「区间按位或」等。

ST 表能较好的维护「可重复贡献」的区间信息(同时也应满足结合律),时间复杂度较低。

可重复贡献问题是指满足 \(x\operatorname{opt} x=x\) 的运算对应的区间询问。

例如,\(\max(x,x)=x\),\(\operatorname{gcd}(x,x)=x\),等等。

所以 RMQ 和区间 GCD 就是一个可重复贡献问题,像区间和就不具有这个性质。

如果预处理区间重叠了,则会导致重叠部分被计算两次,这是我们所不愿意看到的。

#include <bits/stdc++.h>

using namespace std;

constexpr int N = 2e5 + 10;
constexpr int K = 20;

int n, a[N];

int st[N][K];

#define pow2(x) (1 << (x))

void build() {
    for (int i = 1; i <= n; ++i) st[i][0] = a[i];
    for (int k = 1; k < K; ++k) for (int i = 1; i + pow2(k) - 1 <= n; ++i) st[i][k] = max(st[i][k - 1], st[i + pow2(k - 1)][k - 1]);
}

int query(int p, int q) {
    int k = log2(q - p + 1);
    return max(st[p][k], st[q - pow2(k) + 1][k]);
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);
    cin >> n;
    copy_n(istream_iterator<int>(cin), n, a + 1);
    build();
    int q, l, r; cin >> q;
    while (q--) cin >> l >> r, cout << query(l, r) << endl;
    return 0;
}

不支持修改(复杂度很差)。

标签:RMQ,int,mid,复杂度,cin,ST,区间,mathcal,数据结构
From: https://www.cnblogs.com/RainPPR/p/18288455

相关文章

  • 数据结构初阶 遍历二叉树问题(一)
    一.链式二叉树的实现1.结构体代码typedefintBTDateType;typedefstructBinaryTreeNode{ BTDateTypedata; structBinaryTreeNode*left; structBinaryTreeNode*right;}BTNode;大概的图形是这样子2.增删查改我们这里要明确的一点的二叉树的增删查改是没有......
  • 【C++/STL】模板进阶(非类型模板&&类模板打印&&特化&&分离编译)
    ✨                       人生便如一首绝句,平平仄仄平平仄       ......
  • MinGW GCC Boost Serialization 无法定位程序输入点 _ZSt19uncaught_exceptionsv 于动
     在Windows下使用MinGWGCC编译Boost和Demo程序,运行时报错:GCC: gccversion8.1.0(i686-posix-dwarf-rev0,BuiltbyMinGW-W64project)boost:boost1.85.0排查原因是GCC和Boost不匹配,适当降低boost版本后正常。GCC8.1是2018年,Boost1.85.0是2024年,时间差距比较大。......
  • DAY 1 数据结构与算法 (选择排序,冒泡排序,插入排序)
    1.选择排序        选择排序(SelectionSort)是一种简单直观的排序算法。其基本思想是每一次从待排序的数据元素中选择最小(或最大)的一个元素,放在已排好序的元素序列的末尾,直到全部待排序的数据元素排好序为止。即每一次设定一个数为最大或者最小值,然后与其他的数进行交......
  • 缓冲器的重要性,谈谈PostgreSQL
    目录一、PostgreSQL是什么二、缓冲区管理器介绍三、缓冲区管理器的应用场景四、如何定义缓冲区管理器一、PostgreSQL是什么PostgreSQL是一种高级的开源关系型数据库管理系统(RDBMS),它以其稳定性、可靠性和高度可扩展性而闻名。它最初由加州大学伯克利分校开发,现在由......
  • vCenter登录失败报500错误:no healthy upstream
    过了个周末登录vCenter的时候提示:HTTP状态500-内部服务器错误;重启服务后提示:nohealthyupstream。如下图:看到这个情况,肯定就是部分不服务异常了或者压根就没有启动。至于说因为啥异常还不得而知。想着登录管理服务(访问端口:5480)重启一下异常服务,结果提示证书过期。问题......
  • 【Postopia Dev Log】Day 2
    考虑到不确定能把系统做到什么程度,暂时不考虑分布式相关事宜运行./gradlewbootRun热加载不知道为什么没有生效,找来找去没找到原因想直接用dokcer实现,不熟悉docker和dockercompose困难重重根据SpringBootDevToolsAutoRestartandLiveReload一顿操作之后控制台有反应了......
  • 掌握Java 8新特性:Lambda表达式与Stream API详解
    ......
  • 541. Reverse String II
    Givenastringsandanintegerk,reversethefirstkcharactersforevery2kcharacterscountingfromthestartofthestring.Iftherearefewerthankcharactersleft,reverseallofthem.Iftherearelessthan2kbutgreaterthanorequaltokchara......
  • 数据结构——二叉树相关题目
    1.寻找二叉树中数值为x的节点//寻找二叉树中数值为x的节点BTNode*TreeFind(BTNode*root,BTDataTypex)//传过来二叉树的地址和根的地址,以及需要查找的数据{ if(root==Null) { returnNull; }//首先需要先判断这个树是否为空,如果为空直接返回空 if(root->data=......