前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【海贼王的数据航海】ST表——RMQ问题

【海贼王的数据航海】ST表——RMQ问题

作者头像
枫叶丹
发布2024-07-12 10:22:03
580
发布2024-07-12 10:22:03
举报
文章被收录于专栏:C++C++

1 -> RMQ问题

1.1 -> 定义

RMQ (Range Minimum/Maximum Query)即区间最值查询问题指:有一组数据和若干个查询,要求在短时间内回答每个查询[ l ,r ] 内的最值。

1.2 -> 解决策略

  1. 朴素搜索:暴力(BFS/DFS) 时间复杂度O(n)。
  2. 线段树(Segment Tree) 时间复杂度O(n)-O(logn)。
  3. ST表(Sparse Table,稀疏表):倍增思想,O(nlogn)预处理,O(1)查询最值。

2 -> ST表

2.1 -> 定义

ST表(Sparse Table,稀疏表),主要应用倍增思想,是一种用于解决可重复贡献问题数据结构。它通过预处理给定数组,创建一个二维表格,使得任何区间的最小/最大值查询都可以在常数时间内完成。ST表特别适合于静态数据:当数列不经常改变时,它是最有效的。可以实现O(nlogn)预处理、O(1)查询。主要用于解决RMQ问题

2.2 什么是可重复贡献问题

可重复贡献问题是指在某些特定的数学运算中,当运算的性质满足一定条件时,即使是在包含重复部分的区间内进行询问,所得到的结果仍然是相同的问题。这种问题的特点是,它们可以通过预处理所有可能的区间,然后在查询时直接返回预处理的结果来解决。例如,最大值问题和最大公因数问题就是典型的可重复贡献问题,因为它们满足以下性质:

  • 最大值满足 max(x, x) = x
  • 最大公因数满足 gcd(x, x) = x

这些性质意味着,对于任何给定的数 x,其自身与其他任何数的最大值或最大公因数仍然是 x 本身。因此,当我们需要计算一个区间内的最大值或最大公因数时,可以将区间分割成更小的子区间,并利用这些子区间的结果来快速得出整个区间的答案。

2.3 -> 预处理ST表

倍增法递推:用两个等长的小区间拼凑成一个大区间。

f[ i ][ j ] 以第 i 个数为起点,长度为

2^{^{j}}
2^{^{j}}

的区间中的最大值。

理想状态方程:

f[ i ][ j ] = max(f[ i ][ j - 1 ], f[ i + 2^{j - 1}][j - 1])
f[ i ][ j ] = max(f[ i ][ j - 1 ], f[ i + 2^{j - 1}][j - 1])
代码语言:javascript
复制
#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
using namespace std;

const int N = 1e5 + 10;

const int M = 20;

int f[N][M];

int main()
{
	//预处理ST表
	int n = 0;
	int m = 0;
	for (int i = 0; i < n; i++)
		cin >> f[i][0];

	for (int j = 1; j <= M; j++)  //枚举区间长度
		for (int i = 1; i + (1 << j) - 1 <= n; i++)  //枚举起点
			f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);

	return 0;
}

区间终点:

i+ 2^{j}-1\leq n
i+ 2^{j}-1\leq n

假如n = 6 区间长度倍增:1,2,4,8…… f[ i,0 ]:[ 1 1 ][ 2 2 ][ 3 3 ][ 4 4 ][ 5 5 ][ 6 6 ] f[ i,1 ]:[ 1 2 ][ 2 3 ][ 3 4 ][ 4 5 ][ 5 6 ] f[ i,2 ]:[ 1 4 ][ 2 5 ][ 3 6 ]

j=3:i+2^{j}-1=1+8-1>6
j=3:i+2^{j}-1=1+8-1>6

2.4 -> 处理查询

对查询区间[ l,r ]做分割、拼凑。

区间长度的指数:

k=log_{2}(r - l + 1)
k=log_{2}(r - l + 1)

k = 0:{1} k = 1:{2,3} k = 2:{4,5,6,7} k = 3:{8,9,10,11,12,13,14,15}

通过观察可以发现:

2^{k}\leq r-l+1< 2\cdot 2^{k}
2^{k}\leq r-l+1< 2\cdot 2^{k}

即区间[ l,r ]必可以用两个长度为

2^{k}
2^{k}

的区间重叠拼凑

max(f[l][k],f[r-2^{k}+1][k])
max(f[l][k],f[r-2^{k}+1][k])
代码语言:javascript
复制
    int l = 0;
	int r = 0;
	for (int i = 1; i <= m; i++)
	{
		scanf("%d %d", &l, &r);
		int k = log2(r - l + 1);  //区间长度指数

		printf("%d\n", max(f[l][k], f[r - (1 << k) + 1][k]));
	}

[1,4] -> [1,4] + [1,4] [1,5] -> [1,4] + [2,5] [1,6] -> [1,4] + [3,6] [1,7] -> [1,4] + [4,7]

总结:凡是符合结合律且可重复贡献的信息查询都可以使用ST表。显然最大值、最小值、最大公因数、最小公倍数、按位或、按位与都符合这个条件。如果涉及区间修改操作,就要使用线段树解决了。

2.5 -> 实际问题

luogu:P3865

题目链接:P3865 【模板】ST 表

题目背景

这是一道 ST 表经典题——静态区间最大值

题目描述

给定一个长度为 N 的数列,和 M 次询问,求出每一次询问的区间内数字的最大值。

输入格式

第一行包含两个整数 N,M,分别表示数列的长度和询问的个数。

第二行包含 N 个整数(记为 ai​),依次表示数列的第 i 项。

接下来 M 行,每行包含两个整数 𝑙𝑖,𝑟𝑖,表示查询的区间为 [𝑙𝑖,𝑟𝑖]。

输出格式

输出包含 M 行,每行一个整数,依次表示每一次询问的结果。

输入输出样例

输入 #1

代码语言:javascript
复制
8 8
9 3 1 7 5 6 0 8
1 6
1 5
2 7
2 6
1 8
4 8
3 7
1 8

输出 #1

代码语言:javascript
复制
9
9
7
7
9
8
7
9

说明/提示

对于 30%30% 的数据,满足 1≤𝑁,𝑀≤101≤N,M≤10。

对于 70%70% 的数据,满足 1≤𝑁,𝑀≤1051≤N,M≤105。

对于 100%100% 的数据,满足 1≤𝑁≤1051≤N≤105,1≤𝑀≤2×1061≤M≤2×106,𝑎𝑖∈[0,109]ai​∈[0,109],1≤𝑙𝑖≤𝑟𝑖≤𝑁1≤li​≤ri​≤N。

AC代码:

代码语言:javascript
复制
#define _CRT_SECURE_NO_WARNINGS 1

#include <iostream>
#include <cmath>
using namespace std;

const int N = 1e5 + 10;

const int M = 20;

int f[N][M];

int main()
{
	//预处理ST表
	int n = 0;
	int m = 0;
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= n; i++)
		scanf("%d", &f[i][0]);

	for (int j = 1; j <= M; j++)  //枚举区间长度
		for (int i = 1; i + (1 << j) - 1 <= n; i++)  //枚举起点
			f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);

	int l = 0;
	int r = 0;
	for (int i = 1; i <= m; i++)
	{
		scanf("%d %d", &l, &r);
		int k = log2(r - l + 1);  //区间长度指数

		printf("%d\n", max(f[l][k], f[r - (1 << k) + 1][k]));
	}

	return 0;
}

感谢各位大佬支持!!!

互三啦!!!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-07-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 -> RMQ问题
    • 1.1 -> 定义
      • 1.2 -> 解决策略
      • 2 -> ST表
        • 2.1 -> 定义
          • 2.2 什么是可重复贡献问题
            • 2.3 -> 预处理ST表
              • 2.4 -> 处理查询
                • 2.5 -> 实际问题
                  • 题目背景
                    • 题目描述
                      • 输入格式
                        • 输出格式
                          • 输入输出样例
                            • 说明/提示
                            领券
                            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档