Sparse Table

news/2024/10/18 20:07:55/文章来源:https://www.cnblogs.com/ronchen/p/18474958

Sparse Table 可用于解决这样的问题:给出一个 \(n\) 个元素的数组 \(a_1, a_2, \cdots, a_n\),支持查询操作计算区间 \([l,r]\) 的最小值(或最大值)。这种问题被称为区间最值查询问题(Range Minimum/Maximum Query,简称 RMQ 问题)。预处理的时间复杂度为 \(O(n \log n)\),预处理后数组 \(a\) 的值不可以修改,一次查询操作的时间复杂度为 \(O(1)\)

例题:P2880 [USACO07JAN] Balanced Lineup G

有一个包含 \(n\) 个数的序列 \(h_i\),有 \(q\) 次询问,每次询问 \(h_{a_i}, h_{a_i + 1}, \cdots, h_{b_i - 1}, h_{b_i}\) 中最大值与最小值的差。
数据范围:\(1 \le n \le 5 \times 10^4, \ 1 \le q \le 1.8 \times 10^5, \ 1 \le h_i \le 10^6, \ a_i \le b_i\)

分析:题目要求最大值和最小值的差难以直接求出,通常需要分别求解最大值和最小值。最直接的做法是每次遍历区间中的每一个数,记录最大值和最小值。这样可以正确求出正确答案,但是效率低下,时间复杂度高达 \(O(nq)\),无法通过本题。

之所以这样做效率低下,是因为所有询问区间可能有着大量的重叠,这些重叠部分被多次遍历到,因此产生了大量的重复。如果可以通过预处理得到一些区间的最小值,再通过这些区间拼凑每一个询问区间,就可以提高效率。

预处理前缀和可以拼凑出任意区间的和,但是这个思路不能直接搬到最值查询问题中。原因在于区间和可以从一个大区间中减去一部分小区间得到,而区间最值不行,所以只能用小区间去拼出大区间。如何选择预处理的区间就成为关键,选择的区间既要能够拼出任意区间,数量少又不能太多,并且预处理和查询都要高效。

可以预处理以每一个位置为开头,长度为 \(2^0, 2^1, \cdots, 2^{\lfloor \log_2 n \rfloor}\) 的所有区间最值。下面以最大值为例,用 \(f_{i,j}\) 表示 \(h_i, h_{i+1}, \cdots, h_{i+2^j-2}, h_{i+2^j-1}\) 中的最大值,用递推的方式计算所有的 \(f\),转移为 \(f_{i,j} = \max (f_{i,j-1}, f_{i+2^{j-1}, j-1})\)。计算所有的 \(f\) 的过程为预处理,预处理的时间复杂度为 \(O(n \log n)\)

image

void init() {for (int i = 1; i <= n; i++) {f[i][0] = h[i];}for (int j = 1; (1 << j) <= n; j++) {for (int i = 1; i <= n - (1 << j) + 1; i++) {f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);} }
}

接下来解决查询的问题,设需要查询最大值的区间是 \([l,r]\)。记区间长度为 \(L\),则该区间可以拆分为 \(O(\log L)\) 个小区间。对 \(L\) 做二进制拆分,从 \(l\) 开始向后跳,每次跳跃的量是一个 \(2\) 的幂,从而拼出整个区间。单词查询时间复杂度为 \(O(\log n)\)

int query(int l, int r) {int len = r - l + 1, ans = -INF, cur = l;for (int i = 0; (1 << i) <= len; i++) {if ((len >> i) & 1) {ans = max(ans, f[cur][i]);cur += (1 << i);} }return ans;
}

更进一步,查询区间最值时,区间合并的过程允许重叠,因此只需要找到两个长度为 \(2^k\) 的区间合并得到 \([l,r]\)。令 \(k\) 为满足 \(2^k \le r-l+1\) 的最大整数,区间 \([l, l+2^k-1]\) 和区间 \([r-2^k+1,r]\) 合并起来覆盖了需要查询的区间 \([l,r]\)

image

int query(int l, int r) {int k = log_2[r - l + 1]; // 可以预处理log_2的表return max(f[l][k], f[r - (1 << k) + 1][k]);
}
参考代码
#include <cstdio>
#include <algorithm>
using std::min;
using std::max;
const int N = 50005;
const int LOG = 16;
int h[N], f_min[N][LOG], f_max[N][LOG], log_2[N];
void init(int n) {log_2[1] = 0;for (int i = 2; i <= n; i++) log_2[i] = log_2[i >> 1] + 1; // 预处理对数表for (int i = 1; i <= n; i++) {f_min[i][0] = f_max[i][0] = h[i];}for (int j = 1; (1 << j) <= n; j++) {for (int i = 1; i <= n - (1 << j) + 1; i++) {f_min[i][j] = min(f_min[i][j - 1], f_min[i + (1 << (j - 1))][j - 1]);f_max[i][j] = max(f_max[i][j - 1], f_max[i + (1 << (j - 1))][j - 1]);}}
}
int query(int l, int r, int flag) { // flag为1时查询最大值,为0时查询最小值int k = log_2[r - l + 1];return flag ? max(f_max[l][k], f_max[r - (1 << k) + 1][k]) : min(f_min[l][k], f_min[r - (1 << k) + 1][k]);
}
int main()
{int n, q; scanf("%d%d", &n, &q);for (int i = 1; i <= n; i++) scanf("%d", &h[i]);init(n);for (int i = 1; i <= q; i++) {int a, b; scanf("%d%d", &a, &b);printf("%d\n", query(a, b, 1) - query(a, b, 0));}return 0;
}

Sparse Table 预处理部分的时间复杂度为 \(O(n \log n)\),查询一次的时间复杂度为 \(O(1)\),总的时间复杂度为 \(O(n \log n)\)

Sparse Table 不仅可以求区间最大值和最小值,还可以处理符合结合律和幂等律(与自身做运算,结果仍是自身)的信息查询,如区间最大公约数、区间最小公倍数、区间按位或、区间按位与等。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计量经济学(十一)——联立方程模型的估计

img { display: block; margin-left: auto; margin-right: auto } table { margin-left: auto; margin-right: auto } 联立方程模型(Simultaneous Equations Model, SEM)是一类包含多个相互依赖变量的统计模型,用来描述这些变量之间的相互关系。在传统的单一方程模型中,通常…

数据结构与算法 课程随记

数据结构与算法 课程随记因为有时候需要在不同设备编辑同一份文档,本地不太方便了,先在放着博客园比较省事吧。 但是博客园是不是快要四了啊,没事再整一个个人博客吧。 Class https://www.runoob.com/cplusplus/cpp-classes-objects.html大纲 定义成员函数,(无论public/pri…

pve安装后删除local-lvm并把其空间全部分给local

在安装pve的时候,系统默认分配给local的空间非常小,我们可以通过以下方法把local-lvm删除,并将其空间还给local。 在webui的pve节点的磁盘选项中找到LVM-Thin,删除data卷。删除后此处为空。 接着打开终端执行以下命令: lvresize --extents +100%FREE --resizefs pve/root此…

PYNQ Z2 读取xadc外部通道电压

使用XADC 或者JTAG只能读取XADC的内部电压, 而无法读取外部通道的电压 现在使用xsysmon.h库里面的函数进行XADC外部通道的电压 为了方便观察,增加了PL GPIO KEY LED进行观察 1. 配置ZYNQ70002.添加两个axi gpio并进行配置 AXI GPIO0AXI GPIO13. 添加XADC进行配置 这里选择axi l…

10.18 模拟赛

炼石计划 10 月 04 日 NOIP 模拟赛 #8【补题】 - 比赛 - 梦熊联盟 (mna.wang) 复盘 T1 有种 div.2 B 的风格,没秒,想看题。 T2。只判是否无解?\(k \le 100\)?把 \(200\) 个关键连通块拿出来建图跑传递闭包不就做完了。 一遍过大样例?简直不可思议,但还是把 T2 关了吧。 用…

小心!这样分享 B 站视频会暴露身份

已经有被开盒的案例了。‍ 在 2022 年 6 月 10 日 0 点,B 站在视频的网址上加了个参数 ?vd_source=XXXXXXXXXXXXXXX​,如图: ​ 经过网友的测试,这个参数值很可能就是用户 ID 的 hash 值(简单来说就是用户身份),所以如果直接复制网址的话,是有可能被“开盒”的。 ‍ 其…

局部静态变量的初始化观测

局部静态变量的初始化观测//全局变量int global=0x11111;int main(int argc, char* argv[]){ //局部变量 int temp=0x160; global=global+temp; return 0;}6: int global=0x111111;7: int main(int argc, char* argv[])8: {00401010 push …

想玩Steam游戏,但配置太低?ToDesk云电脑一招搞定!

在游戏爱好者的世界里,汇集了许多游戏大作的Steam平台无疑是一座宝库。但对于许多玩家来说,拥有一颗渴望畅玩游戏的心,却常常被低配置的电脑设备所束缚。尤其是面对硬件要求极高的3A大作时,低配置的电脑往往力不从心,卡顿、掉帧等问题让人苦恼不已。但别担心!小编最近发现…

孩子对手机有了渴望,家长该如何应对?ToDesk远程防沉迷

在现代生活中,手机已经成为我们密不可分的生活工具,日常工作社交生活都要靠手机来完成。 但近年来,手机的各类视频游戏等app诱惑在不断加大,导致孩子总是抱着手机不放,家长对此类问题头疼不已。 ToDesk远程控制软件可以另辟蹊径用远程控制软件解决掉孩子手机沉迷问题,只需…

vscode中整合豆包MarsCode编程助手

豆包MarsCode是字节跳动旗下的一款AI工具,最近在刷帖子时看到已经可以在vscode中通过插件安装MarsCode工具,接下来我们来看下操作流程以及使用效果。 第一步:首先需要注册下豆包账号 豆包 MarsCode--智能编码,一触即发! 第二步:打开vscode 后,左侧导航栏上点击扩展,搜索…

E-拼接串

题目: 思路:在已有的数组中寻找符合条件,也就是没有重复数字的子数组,以掩码的对应位的形式来表示当前子数组元素的存在,之后双重循环生成所有子数组,内层循环中,判断当前元素是否存在掩码中,存在则推出,不存在则加入掩码并标记。用另一个循环来更新 sum 数组,使得每…

低空经济如何实现商业化

随着技术的进步和政策的支持,低空经济正逐渐成为推动经济发展的新引擎。低空经济,主要指利用低空空域资源,通过有人驾驶和无人驾驶航空器的低空飞行活动,带动相关领域融合发展的综合性经济形态。当前,低空经济的商业化正面临前所未有的机遇与挑战。 技术突破是基础技术是推…