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 ...
随机推荐
- VK Cup 2017 - Round 1 (CDE)
771C Bear and Tree Jumps 大意: 给定树,每步能走到距离不超过$k$的任意点,记$f(s,t)$为$s$到$t$的最少步数,求$\sum\limits_{s<t}f(s, ...
- 调用WebService时加入身份验证,以拒绝未授权的访问
众所周知,WebService是为企业需求提供的在线应用服务,其他公司或应用软件能够通过Internet来访问并使用这项在线服务.但在有些时候的某些应用服务不希望被未授权访问,那么此时我们可以一下几种 ...
- linux 命令行 光标移动技巧等
看一个真正的专家操作命令行绝对是一种很好的体验-光标在单词之间来回穿梭,命令行不同的滚动.在这里强烈建立适应GUI节目的开发者尝试一下在提示符下面工作.但是事情也不是那么简单,还是需要知道“如何去做” ...
- Spark机器学习基础-监督学习
监督学习 0.线性回归(加L1.L2正则化) from __future__ import print_function from pyspark.ml.regression import Linea ...
- Java源码阅读之ArrayList
基于jdk1.8的ArrayList源码分析. 实现List接口最常见的大概就四种,ArrayList, LinkedList, Vector, Stack实现,今天就着重看一下ArrayList的源 ...
- 【转载】 Asp.Net MVC网站提交富文本HTML标签内容抛出异常
今天开发一个ASP.NET MVC网站时,有个页面使用到了FCKEditor富文本编辑器,通过Post方式提交内容时候抛出异常,仔细分析后得出应该是服务器阻止了带有HTML标签内容的提交操作,ASP. ...
- 理解ld-linux.so.2
翻译自:Understanding ld-linux.so.2 前言 ld-linux.so.2是linux的动态加载器(dynamic loader).本文试图就ld-linux.so.2如何与Li ...
- 2018 ACMICPC上海大都会赛重现赛 H - A Simple Problem with Integers (线段树,循环节)
2018 ACM 国际大学生程序设计竞赛上海大都会赛重现赛 H - A Simple Problem with Integers (线段树,循环节) 链接:https://ac.nowcoder.co ...
- Linux网络编程综合运用之MiniFtp实现(六)
间隔了一周时间没写了,由于今年的股势行情貌似不错的样子,对于对股市完全不懂的我也在蠢蠢欲动,所以最近一周业余时间在“不务正业”-----学习炒股.发现学习它其实挺费神的,满脑子都是走势图,而且是神经有 ...
- machine learning(10) -- classification:logistic regression cost function 和 使用 gradient descent to minimize cost function
logistic regression cost function(single example) 图像分布 logistic regression cost function(m examples) ...