【算法基础】你见过ST表吗?它竟然这么强大

文章目录

    • ST表(Sparse Table)
      • 观察
      • 预处理
      • 区间求和
      • 区间最小值查询

ST表(Sparse Table)

ST表是一种用于区间查询的数据结构。它上面大部分的区间查询都是 O ( l o g n ) O(logn) O(logn)的时间。但它在查询区间最大值最小值问题上非常有效,只需要 O ( 1 ) O(1) O(1)的时间。

这种数据结构唯一的缺点是只能用于不可变的数组,就是说不支持更新操作。如果数组中元素更新了,那整个数据结构都要重新构造。

观察

任何一个非负整数都可以唯一表示为一组递减的2的幂的和,这等价于一个数的二进制表达。例如, 13 = ( 1101 ) 2 = 8 + 4 + 1 13 = (1101)_2 = 8 + 4 + 1 13=(1101)2=8+4+1。对于一个数 x x x最多需要 ⌈ l o g 2 x ⌉ \lceil log_2x \rceil log2x项。

同样的,任何一个区间都可以被唯一的表示为一组长度为2的幂的不相交区间的并集。比如, [ 2 , 14 ] = [ 2 , 9 ] ∪ [ 10 , 13 ] ∪ [ 14 , 14 ] [2,14] = [2,9] \cup [10,13] \cup [14,14] [2,14]=[2,9][10,13][14,14]。其中 [ 2 , 14 ] [2,14] [2,14]区间长度为13,而组成它的三个区间长度分别为8,4,1。同理,区间的数量不超过 ⌈ l o g 2 ( 区间长度 ) ⌉ \lceil log_2(区间长度) \rceil log2(区间长度)⌉

ST表的关键就是提前计算出所有长度为2的幂的区间的查询。之后任何一个查询都可以被分解成这些已知的查询的和。

预处理

我们使用一个二位数组来保存预处理的数据。 s t [ i ] [ j ] st[i][j] st[i][j]保存长度为 2 i 2^i 2i并且左端点为 j j j,即区间为 [ j , j + 2 i − 1 ] [j,j+2^i-1] [j,j+2i1]查询。这个二维数组的大小是 ( K + 1 ) × M A X N (K+1) \times MAXN (K+1)×MAXN,其中 M A X N MAXN MAXN是区间的最大长度。 K K K需要满足 K > ⌈ l o g 2 M A X N ⌉ K> \lceil log_2 MAXN \rceil K>log2MAXN,这是因为 2 l o g 2 M A X N 2^{log_2MAXN} 2log2MAXN是我们需要预处理保存的最长的区间。对于元素数量小于等于1e7的问题, K = 25 K=25 K=25就足够了。

由于计算机缓存的机制的存在, M A X N MAXN MAXN这一维放到数组的第二个维度比较快。

int st[K + 1][MAXN];

因为区间 [ j , j + 2 i − 1 ] [j,j+2^i - 1] [j,j+2i1]可以完美地被分解为区间 [ j , j + 2 i − 1 − 1 ] [j,j+2^{i-1}-1] [j,j+2i11]和区间 [ j + 2 i − 1 , j + 2 i − 1 ] [j+2^{i-1},j+2^i-1] [j+2i1,j+2i1]的并。我们可以通过动态规划的方法来高效地生成预处理的表。

std::copy(array.begin(), array.end(), st[0]);for (int i = 1; i <= K; i++)for (int j = 0; j + (1 << i) <= N; j++)st[i][j] = f(st[i - 1][j], st[i - 1][j + (1 << (i - 1))]);

函数 f f f取决于查询的类型,对于求和的查询就是求和函数,对于最小值的查询就是求最小值函数。

预处理的时间复杂度是 O ( N l o g N ) O(NlogN) O(NlogN)

区间求和

对于区间求和的查询,函数 f f f就是 f ( x , y ) = x + y f(x,y) = x + y f(x,y)=x+y。我们可以用下面的代码构造数据结构:

long long st[K + 1][MAXN];std::copy(array.begin(), array.end(), st[0]);for (int i = 1; i <= K; i++)for (int j = 0; j + (1 << i) <= N; j++)st[i][j] = st[i - 1][j] + st[i - 1][j + (1 << (i - 1))];

为了回答区间 [ L , R ] [L,R] [L,R]的区间查询,我们从大到小迭代2的幂,只要当前 2 i 2^i 2i小于等于区间的长度( R − L + 1 R-L+1 RL+1),我们就把区间 [ L , L + 2 i − 1 ] [L,L+2^i-1] [L,L+2i1]的结果加上,继续求区间 [ L + 2 i , R ] [L+2^i,R] [L+2i,R]的结果。

long long sum = 0;
for (int i = K; i >= 0; i--) {if ((1 << i) <= R - L + 1) {sum += st[i][L];L += 1 << i;}
}

区间求和的时间复杂度为 O ( K ) O(K) O(K),即 O ( l o g M A X N ) O(logMAXN) O(logMAXN)

区间最小值查询

区间最值查询就是ST表真正擅长的地方了(It shines in this type of query.)。当查询区间最小值的时候,区间的重叠对结果没有影响。因为相对于把区间分解成多个不相交的区间,我们可以把区间分解成两个长度为2的幂的两个区间,这两个区间可能重叠也可能不重叠。比如,我们可以把区间 [ 1 , 6 ] [1,6] [1,6]分解为区间 [ 1 , 4 ] [1,4] [1,4]和区间 [ 3 , 6 ] [3,6] [3,6]。很显然区间 [ 1 , 6 ] [1,6] [1,6]的最小值,就是区间 [ 1 , 4 ] [1,4] [1,4]和区间 [ 3 , 6 ] [3,6] [3,6]的最小值的最小值。所以我们可以通过下面的式子计算区间 [ L , R ] [L,R] [L,R]的最小值:
m i n ( s t [ i ] [ L ] , s t [ i ] [ R − 2 i + 1 ] ) 其中 i = l o g 2 ( R − L + 1 ) min(st[i][L], st[i][R-2^i + 1]) \quad \text{其中} i=log_2(R-L+1) min(st[i][L],st[i][R2i+1])其中i=log2(RL+1)
这个式子里还需要高效地计算 l o g 2 ( R − L + 1 ) log_2(R-L+1) log2(RL+1)的值,这个可以通过预处理计算出所有需要的log值:

int lg[MAXN+1];
lg[1] = 0;
for (int i = 2; i <= MAXN; i++)lg[i] = lg[i/2] + 1;

log值也可以在常数时间内动态的计算:

// C++20
#include <bit>
int log2_floor(unsigned long i) {return std::bit_width(i) - 1;
}// pre C++20
int log2_floor(unsigned long long i) {return i ? __builtin_clzll(1) - __builtin_clzll(i) : -1;
}

压力测试表示使用lg数组计算会更慢一些,这是因为计算机缓存机制的存在。

查询区间 [ L , R ] [L,R] [L,R]结果的代码如下:

int i = lg[R - L + 1];
int minimum = min(st[i][L], st[i][R - (1 << i) + 1]);

区间最小值查询的时间复杂度为 O ( 1 ) O(1) O(1)

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

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

相关文章

算法课程笔记——蓝桥云课第11次直播

算法课程笔记——蓝桥云课第11次直播

收藏与品鉴:精酿啤酒的艺术之旅

啤酒&#xff0c;这一古老的酒精饮品&#xff0c;不仅是人们生活中的日常饮品&#xff0c;更是一种艺术和文化的载体。对于Fendi club啤酒而言&#xff0c;收藏与品鉴更是一门深入骨髓的艺术之旅。 Fendi club啤酒的收藏&#xff0c;不仅仅是简单的存放和保管&#xff0c;而是一…

交换机组网最常见的8大故障及解决方式

有朋友多次提到网络故障&#xff0c;其中在交换机组网时常见的故障比较多&#xff0c;为了便于大家排除这些故障&#xff0c;在此介绍一些常见的典型故障案例及处理思路。 故障1&#xff1a;交换机刚加电时网络无法通信 【故障现象】 交换机刚刚开启的时候无法连接至其他网络…

数据库面试题(MySQL、Oracle)

数据库 数据库的四大特性 原子性&#xff1a; 事务中的所有操作要么全部执行成功&#xff0c;要么全部执行失败&#xff0c;不存在部分执行的情况&#xff1b;成功必须要完全应用到数据库&#xff0c;失败则不能对数据库产生影响&#xff1b; 一致性&#xff1a; 事务在执…

Java面向对象——接口的定义与实现

普通类&#xff1a;只有具体实现 抽象类&#xff1a;具体实现和规范&#xff08;抽象方法&#xff09;都有 接口&#xff1a;只有规范。自己无法写方法。专业的约束&#xff01;约束和实现分离&#xff1a;面向接口编程 接口就是规范&#xff0c;定义的是一组规则&#xf…

k8s StatefulSet

Statefulset 一个 Statefulset 创建的每个pod都有一个从零开始的顺序索引&#xff0c;这个会体现在 pod 的名称和主机名上&#xff0c;同样还会体现在 pod 对应的固定存储上。这些 pod 的名称是可预知的&#xff0c;它是由 Statefulset 的名称加该实例的顺序索引值组成的。不同…

现货黄金在线交易有哪些优势_EE trade

现货黄金在线交易拥有几项独特优势&#xff0c;使其成为广受投资者青睐的贵金属投资方式&#xff1a; 1. 全天候交易 现货黄金市场几乎可以实现24小时不间断交易&#xff0c;投资者可以根据全球市场的变动随时参与交易&#xff0c;这提供了极大的灵活性和即时反应市场变化的能…

PyTorch 中构建神经网络的常用方法介绍

在 PyTorch 中构建神经网络通常有以下几种方法。每种方法都有其特定的应用场景&#xff0c;选择哪种方法取决于你的具体需求&#xff0c;例如模型的复杂度、是否需要多 GPU 训练、是否需要自定义层或操作等。在实践中&#xff0c;这些方法往往是相互结合使用的&#xff0c;以达…

Mysql 如何定位慢查询?

定位MySQL中的慢查询&#xff0c;就像侦探查找案件线索一样&#xff0c;一步步找到让数据库运行变慢的原因。 打开慢查询日志&#xff1a; 首先&#xff0c;得让MySQL开始记录那些跑得慢的查询。这就像是安装了一个监控摄像头&#xff0c;记录下所有的“嫌疑人”。在MySQL里&…

Nginx+Keepalived高可用集群

NginxKeepalived高可用集群 服务器准备 服务器名IP软件包主从n1RIP 192.168.99.111 VIP 192.168.99.200nginx keepaliveMASTERn2RIP192.168.99.122 VIP 192.168.99.200nginx keepalivedh1RIP 192.168.99.133 VIP 192.168.99.200httpdh2RIP 192.168.32.144 VIP 192.168.99.200h…

playwright 自动化框架python教程(七)

使用with语句管理资源生命周期后&#xff0c;还需要page.close()和context.close()吗&#xff1f; 当使用 with 语句管理 Playwright 的资源生命周期时&#xff0c;通常情况下不需要再显式调用 page.close() 和 context.close()。这是因为 with 语句会在其代码块执行完毕后自动…

从入门到精通:.gitlab-ci.yml文件的完整指南

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 从入门到精通&#xff1a;.gitlab-ci.yml文件的完整指南 前言.gitlab-ci.yml文件概述stagesimagesbefore_script和after_scripttagsonly和exceptonly关键字except关键字 artifacts使用方式产物路径其他…

写一个类ChatGPT应用,前后端数据交互有哪几种

❝ 对世界的态度&#xff0c;本质都是对自己的态度 ❞ 大家好&#xff0c;我是「柒八九」。一个「专注于前端开发技术/Rust及AI应用知识分享」的Coder 前言 最近&#xff0c;公司有一个AI项目&#xff0c;要做一个文档问答的AI产品。前端部分呢&#xff0c;还是「友好借鉴」Cha…

结项评审报告

项目名称&#xff0c;《结项评审报告》 项目名称项目编号本文件标识符Company-Project-PCM-REVIEW项目承担部门项目经理立项时间开发完成时间结项评审时间 目 录 0. 基本信息 3 1. 项目资产检查与处理 4 2. 项目综合评估 4 2.1 项目完成情况评估 4 2.2 项目质量评估 4 …

C++后端领域聚焦——存储系统和分布式系统

编程语言和脚本 C/C: 作为核心技能&#xff0c;需要深入理解并熟练使用 C/C 进行开发。Shell: 掌握常用的 Shell 脚本&#xff0c;有助于自动化日常任务和环境配置。Python: 常用于脚本编写、自动化测试、数据处理等&#xff0c;提高开发效率。 计算机基础 数据结构和算法: …

【小程序】怎么优化小程序的性能

优化小程序的性能是提高用户体验和确保应用顺畅运行的关键。以下是一些优化小程序性能的方法&#xff1a; 1. 代码优化2. 图片优化3. 网络请求优化4. 页面渲染优化5. 分包加载6. 使用性能分析工具7. 后端优化8. 用户体验优化 1. 代码优化 精简代码&#xff1a;删除不必要的代码…

16.ABA问题

文章目录 ABA问题1.什么是ABA问题&#xff1f;2.ABA问题解决方案2.1.使用AtomicStampedReference解决ABA问题2.2.使用AtomicMarkableReference解决ABA问题 ABA问题 因为CAS操作的原子性能高&#xff0c;在JUC中广泛被应用&#xff0c;但是如果使用的不合理&#xff0c;CAS操作就…

算法 - hash表 - 2244. 完成所有任务需要的最少轮数 思路题解

2244. 完成所有任务需要的最少轮数 文章目录 [2244. 完成所有任务需要的最少轮数](https://leetcode.cn/problems/minimum-rounds-to-complete-all-tasks/description/)说明题解思路hash表 Codehash表 说明 给你一个下标从 0 开始的整数数组 tasks &#xff0c;其中 tasks[i] …

6 逻辑回归评分卡

6 逻辑回归评分卡 学习目标 掌握KS值的计算方法知道评分映射方法1 模型构建流程 1.1 实验设计 新的模型能上线一定要比原有方案有提升,需要通过实验证明 冷启动业务初期成长期波动期策略调整新增数据源人工审核人工审核新旧模型对比新旧模型对比避免迭代模型新旧模型对比规…

数据结构【顺序表】

文章目录 1.顺序表的概念线性表物理结构逻辑结构 2.顺序表的分类2.1静态顺序表2.2动态顺序表 3.顺序表接口的实现头文件(SQList.h)如下源文件初始化顺序表销毁顺序表插入扩容尾插头插 封装扩容函数删除尾删头删 查找元素在指定位置前插入数据情况一(指定的位置不是首元素)情况二…