ST表 「 从入门到入门 · 浅显理解 」
ST 表是个好东西,虽然前些天 ldq 学长已经讲完啦,但是那天他讲了那么多,让智商受限的我完全没有全部接受,选择性的扔掉了一部分(其实不舍的扔,记不住QAQ)。
ST 表最简单的应用就是查询区间最大值(或着最小值,这里以最大值为例),它(单纯 ST 表自己)需要你先修改之后(如果有修改要求),得到一个确切数组之后,经过 O ( nlogn ) 的预处理,然后就可以做到 O ( 1 ) 查询啦。
ST 表的预处理操作:
对于一个有 n 个数的 a [ n ] ,如果需要用一个二维数组 f [ n ] [ t ] ,其中 n 是指的用这 n 个数,t 是指的 n 最大是 2 的多少次幂,即 2 ^ t >= n 向上取整。
数组 f [ n ] [ t ] 是用来干什么的呢?f [ i ] [ j ] 是指以 a [ n ] 中第 i 个数开始,长度为 2 ^ j 的最大值,这样就清楚了数组 f [ n ] [ t ] 中 t 的来源啦吧。
所以我们要做的第一步预处理中:
f [ i ] [ 0 ] 就是存的 a [ i ] 值自己。
f [ i ] [ 1 ] 就是存的从 a [ i ] 开始往后一个,即 a [ i ] 和 a [ i + 1 ] 的最大值
……
以此类推,就可以得到我们想要的数组 f [ n ] [ t ] 啦。
那么我们怎么去实现这个东西呢?不能一个个的去枚举吧,那样的话,还不如用线段树(我是这么想得H_H),当然啦,这个问题在 ST 表被想出来的时候就解决啦,那就是递推得到,先看一下代码(不理解没关系,慢慢看)。
int f[maxn][20];
int a[maxn];
int n;
void st()
{
for(int i = 1; i <= n; i ++) f[i][0] = a[i];
int t = log(n) / log(2) + 1;
for(int j = 1; j < t; 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]);
}
}
}
第一个 for 循环 应该没什么理解障碍,就是上面说的把自己存进去,因为是 2 ^ 0 。
第二个是两个 for 循环,也就是递推的部分,我们这样子来实现:
f [ i ] [ j ] 代表以 a [ i ] 开始长度为 2 ^ j 的数里面的最大值,即 f [ i ] [ j ] = max ( a[ i ] , …… , a [ i + 2 ^ j ] )。
我们先看一个简单的例子:现在一个数列是 a [ ] = { 1 ,2,3,4,5} , 那么 (下标)0 ~ 2的最大值 Max1 ,和 3 ~ 4 最大值 Max2,两个里面的最大值 Max 就是整个区间的最大值,这个很好理解吧!
那么我们回到求 f [ i ] [ j ] 上,这个问题就变的和这个一样子啦,不过就是需要改变一下长度,我们把这个长度 len = 2 ^ j 的区间分成长度分别为 len1 = 2 ^ ( j - 1 ) 和 len2 = 2 ^ ( j - 1 ) 的这两个区间,只要求出来这两个的最大值就可以像上面那样子得到最终结果啦。
所以我们就可以理解上面我说的意思啦:f [ i ] [ j - 1] 代表从 a [ i ] 开始前 2 ^ ( j - 1 ) 个元素的最值,f [ i + ( 1 << ( j - 1 ) )] [ j - 1 ] 就是后面这 2 ^ ( j - 1 ) 个元素里面的最值,这样子合并取个最大值,就是总的最大啦,也就是代码中的:f [ i ] [ j ] = max ( f [ i ] [ j - 1 ] , f [ i + ( 1 << ( j - 1 ) ) ] [ j - 1 ] ) 。
这里有几点需要注意的(自己xj说的,不对可以告诉我哈):
第一点是大家都知道的,在预处理中控制第二维的循环,也就是 for ( int j = 1; j <= t; j ++) ,一般的话 t 取 20 左右就可以啦,你要是不放心就先计算一下再开数组一样的,这个一定要放在外面,因为我们要通过递推得到,如果放在里面的话,就得不到我们想要的结果啦(可以感觉一下子)。
第二点就是那个 f [ i ] [ j ] 这里可能有理解误区,就算是不够 2 的整数次幂也没有关系的,初始化或者边界处理一下就可以啦,最大值最小值对应上相应的初始化。
第三点是对于 1 << ( j - 1 ) 这个东西,这和求那个 t 的时候的意思一个样子啦,这样子写比较高大尚一些。
ST 表在预处理时采用倍增和DP思想。
ST 表查询操作:
关于查询操作,想一想怎么样子可以做到 O ( 1 ) 查询的呢。
先来看简单的栗子(简单的看懂啦,难得就可以啦):
a [ ] = { 1,2,4,5,6,3,6,8,7,0 },在这些数里面我们想知道 1 ~ 8(下标从 0 开始) 的最大值。
如果我们已经用数组 f [ n ] [ t ] 存好啦,我们可以先计算一下长度可以是 2 的多少次幂,左端点是 x = 1, 右端点是 y = 8,长度 m = log ( y - x + 1) / log ( 2 ),我们需要差的就是从 a [ x ] 开始 m 这么长的区间,由于 m 存在边界问题,所以我们还需要查的区间就变成 [ x ] [ m ] ,但是这样子查的话不免可能会漏掉东西而且预处理的结果我们也没有用到,所以我们把这个 m 的长的区间分成啦两个部分,也就可以利用预处理的结果啦。
所以区间就变成了 [ x ] [ x + 2 ^ m - 1 ] 和 [ y - 2 ^ m + 1] [ y ] ,这两个区间分别对应的数组 f [ n ] [ t ] 是 f [ x ] [ m ] 和 f [ y - ( 1 << m ) + 1 ] [ m ] (这个可能存在不是很好理解的问题,不过不要忘记啦 f [ i ] [ j ] 的意思,是指从 a [ i ] 开始的长度为 2 ^ j 的最值,这样就可以啦,实在不好理解,可以手动画一画)。
代码:
int query(int x, int y)
{
int t = log(abs(y-x + 1))/ log(2);
int a = f[x][t];
int b = f[y - (1 << t) + 1][t];
return max(a,b);
}
const int maxn = 1000004;
int f[maxn][20];
int a[maxn];
int n;
void st()
{
for(int i = 1; i <= n; i ++) f[i][0] = a[i];
int t = log(n) / log(2) + 1;
for(int j = 1; j < 20; 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]);
}
}
}
int query(int x, int y)
{
int t = log(abs(y-x + 1))/ log(2);
int a = f[x][t];
int b = f[y - (1 << t) + 1][t];
return max(a,b);
}
---------------------
作者:Mercury_Lc
就罗嗦这么多啦,还有好多作业QAQ(看在我这么惨的份上,要是转载,别忘记啦我的地址QWQ)
ST表 「 从入门到入门 · 浅显理解 」的更多相关文章
- ST表入门学习poj3264 hdu5443 hdu5289 codeforces round #361 div2D
ST算法介绍:[转自http://blog.csdn.net/insistgogo/article/details/9929103] 作用:ST算法是用来求解给定区间RMQ的最值,本文以最小值为例 方 ...
- 【基础算法-ST表】入门 -C++
前言 学了树状数组看到ST表模板跃跃欲试的时候发现完全没思路,因为给出的查询的时间实在太短了!几乎是需要完成O(1)查询.所以ST表到底是什么神仙算法能够做到这么快的查询? ST表 ST表是一个用来解 ...
- st表树状数组入门题单
预备知识 st表(Sparse Table) 主要用来解决区间最值问题(RMQ)以及维护区间的各种性质(比如维护一段区间的最大公约数). 树状数组 单点更新 数组前缀和的查询 拓展:原数组是差分数组时 ...
- 「ZJOI2018」胖(ST表+二分)
「ZJOI2018」胖(ST表+二分) 不开 \(O_2\) 又没卡过去是种怎么体验... 这可能是 \(ZJOI2018\) 最简单的一题了...我都能 \(A\)... 首先我们发现这个奇怪的图每 ...
- 「学习笔记」ST表
问题引入 先让我们看一个简单的问题,有N个元素,Q次操作,每次操作需要求出一段区间内的最大/小值. 这就是著名的RMQ问题. RMQ问题的解法有很多,如线段树.单调队列(某些情况下).ST表等.这里主 ...
- 「LuoguP3865」 【模板】ST表 (线段树
题目背景 这是一道ST表经典题——静态区间最大值 请注意最大数据时限只有0.8s,数据强度不低,请务必保证你的每次查询复杂度为 O(1) 题目描述 给定一个长度为 N 的数列,和 M 次询问,求出每一 ...
- [模板]ST表浅析
ST表,稀疏表,用于求解经典的RMQ问题.即区间最值问题. Problem: 给定n个数和q个询问,对于给定的每个询问有l,r,求区间[l,r]的最大值.. Solution: 主要思想是倍增和区间d ...
- SAP模块一句话入门(专业术语的理解)
SAP模块一句话入门(专业术语的理解) SAP一句话入门:Financial & Controlling Accounting (FICO) 财务,财务,呵呵,让我们关心一下给我发工资的部门. ...
- [译]:Xamarin.Android开发入门——Hello,Android深入理解
返回索引目录 原文链接:Hello, Android_DeepDive. 译文链接:Xamarin.Android开发入门--Hello,Android深入理解 本部分介绍利用Xamarin开发And ...
随机推荐
- IEEE754浮点数
前言 Go语言之父Rob Pike大神曾吐槽:不能掌握正则表达式或浮点数就不配当码农! You should not be permitted to write production code if ...
- sql For xml path('') 备忘
sql 合并行使用的两个函数记录: SELECT CityName,STUFF((SELECT ',' + UserName FROM table1 subTitle WHERE CityName=A ...
- python学习笔记(CMD运行文件并传入参数)
好久没更新博客了 最近换了份新工作 有时间来整理一篇 在命令行CMD中执行文件过程中如何传入并识别参数 # -*- coding: utf-8 -*- # CMD运行类 # 作者: # 时间: 201 ...
- pymysql操作mysql数据库
1.建库 import pymysql # 建库 try: conn=pymysql.connect( host='127.0.0.1', port=3306, user='root', passwd ...
- ceph集群部署(基于jewel版)
环境 两个节点:ceph1.ceph2 ceph1: mon.mds.osd.0.osd.1 ceph2: osd.2.osd.3 网络配置: ceph1: 管理网络,eth0,10.0.0.20 存 ...
- nginx全局配置和性能优化
nginx目录结构和命令 1.ls /apps/nginx/: html是测试页,sbin是主程序 2.ls /apps/nginx/sbin/: nginx 只有一个程序文件 3. ...
- 【OF框架】配置信息Config添加配置和代码调用api
一.配置规范 配置信息全部写在OF.WebShell项目文件config.json中 配置键使用OF.开头,配置格式如下: { "OF.IgnoredUrl": "log ...
- Java【tomcat】配置文件
Tomcat(二):tomcat配置文件server.xml详解和部署简介 分类: 网站架构 本文原创地址在博客园:https://www.cnblogs.com/f-ck-need-u/p/ ...
- charles 手机抓包设置
本文参考:charles 抓包手机 charles经常会进行手机上的网页抓包,比如去copy别人网站图片或脚本的时候o(∩_∩)o : 手机抓包的原理,和PC类似,手机依靠charles与服务端进行对 ...
- node中的npm的使用
1.node中npm的使用 nodejs软件 1.安装nodejs 自带了npm npm install Bootstrap 好比python自带pip pip3 install requests ...