ST表学习总结
前段时间做16年多校联合赛的Contest 1的D题(HDU 5726)时候遇到了多次查询指定区间的gcd值的问题,疑惑于用什么样的方式进行处理,最后上网查到了ST表,开始弄得晕头转向,后来才慢慢找到了一点门道,于是把这些东西都写下来,以备不时之需。
关于ST表:
首先需要特别说明,ST表的适用范围主要用于区间查询,因为如果要涉及更改的话需要改变整个ST表的值,在理论上,ST表建表的复杂度为O(nlogn),比线段树的单点更新的O(logn)还是要高一些的,面对大量修改操作的时候有超时风险,故不推荐在需要单点更新的更不用说区间更新题目中使用。
含义:那么在原理上,ST表中的某一点代表的的是原数据集中一段区间的特殊值,比如最大值,最小值,最大公约数等。以最大值为例,ST表中一点st[i][j],代表数据集中标号为i到i+2^j-1的区间的最大值。
推导:使用递归公式:st[i][j] = max(st[i][j-1],st[i+2^(j-1)][j-1])可以计算出st表中各点的值,其原理是,将(i,i+2^j-1)这个区间分开成(i,i+2^(j-1)-1)和(i+2^(j-1),i+2^j-1)这两个区间,然后比较这两个区间哪个大,并将大的保留,即为st(i,j)的值,使用了动态规划和贪心的思想,将区间划分为多个小区间,之后再整合。
查询:ST表本质还是用来帮助我们快速查找区间的特殊知道,但是根据刚刚我们对ST的介绍,我们可以很快发现ST表中好像只存储了长度为2^j的区间的值,但是我们平时的查询中,区间长度肯定不可能都恰好等于2^j,那我们怎么去查询那些区间长度不为2^j的特殊值呢,其实方法很简单,就是切割这个区间。把这个区间分为两个长度为2^(j-1)的子区间(两个子区间可能会有重叠部分,但是不会对结果产生影响)。这样,我们对这两个子区间进行查询,之后求出从这两个子区间求出的最大值谁更大,就把哪个定为原区间的最大值就好了。因为2^(j-1)已经在st数组中存放好,所以可以得到快速的得到结果。因为一次查询只要读取数组中两个点的值,所以复杂度为O(1)。
下面给两个样题,希望能对大家有帮助:
第一个题是UESTC-1591(点击可以查看原题),题目要求求指定区间的最大值与最小值的差,原本是一个线段树的样题,但是看了ST表以后,感觉用ST表写起来会更方便一些,其中既包括了求最大值,也包括了求最小值,比较有代表性。下面是ST表写完的AC代码:
#include <stdio.h>
#include <math.h>
#include <algorithm>
#include <iostream>
using namespace std; const int maxn=; int stmax[maxn][];
int stmin[maxn][]; int n,m; void ST() {
int k=int(log(1.0*n)/log(2.0));
for(int j=; j<=k; j++) {
for(int i=; i+(<<j)-<=n; i++) {
stmax[i][j]=max(stmax[i][j-],stmax[i+(<<(j-))][j-]);
stmin[i][j]=min(stmin[i][j-],stmin[i+(<<(j-))][j-]);
}
}
} int qmax(int l,int r) {
int k=int(log(1.0*(r-l+))/log(2.0));
return max(stmax[l][k],stmax[r-(<<k)+][k]);
} int qmin(int l,int r) {
int k=int(log(1.0*(r-l+))/log(2.0));
return min(stmin[l][k],stmin[r-(<<k)+][k]);
} int main() {
scanf("%d %d",&n,&m);
for(int i=; i<=n; i++) {
int temp;
scanf("%d",&temp);
stmax[i][]=stmin[i][]=temp;
}
ST();
for(int i=; i<m; i++) {
int a,b;
scanf("%d %d",&a,&b);
int ans=qmax(a,b)-qmin(a,b);
printf("%d\n",ans);
} return ;
}
之后的第二个样题是HDU 5726,是求一个区间的最大公约数,并且同时输出有多少个区间和这个区间的最大公约数相同。因为这个题目需要知道有多少个区间的最大公约数和那个区间相同,考虑到规模很明显不能现算,所以用ST表是一种不错的选择,这个题目同时还涉及到了gcd的不会递增的性质和二分查找,大家只需要关注一下ST表的建立和查询那部分就好了。
AC代码:
#include <stdio.h>
#include <math.h>
#include <map>
#include <string.h>
#include <iostream>
using namespace std;
const int maxn=;
map<int,long long> mp; int gcd(int a,int b){
if(b==){
return a;
}
return gcd(b,a%b);
} int n,m;
int st[maxn][]; void ST(){
int k=int(log(1.0*n)/log(2.0));
for(int j=;j<=k;j++){
for(int i=;i+(<<j)<=n;i++){
st[i][j]=gcd(st[i][j-],st[i+(<<(j-))][j-]);
}
}
} int query(int l,int r){
int k=int(log(1.0*(r-l+))/log(2.0));
return gcd(st[r-(<<k)+][k],st[l][k]);
} int main(){
int T;
scanf("%d",&T);
for(int cas=;cas<=T;cas++){
memset(st,,sizeof(st));
mp.clear();
scanf("%d",&n);
for(int i=;i<n;i++){
scanf("%d",&st[i][]);
}
ST();
for(int i=;i<n;i++)
{
int t,ll=i;
while(ll<n)
{
t=query(i,ll);
int l=ll,r=n-;
while(l<r)
{
int mid=(l+r+)>>;
if(query(i,mid)>=t)l=mid;
else r=mid-;
}
mp[t]+=l-ll+;
ll=l+;
}
}
int q;
scanf("%d",&q);
printf("Case #%d:\n",cas);
while(q--)
{
int l,r;
scanf("%d%d",&l,&r);
l--,r--;
printf("%d %I64d\n",query(l,r),mp[query(l,r)]);
} }
return ;
}
ST表学习总结的更多相关文章
- ST表学习笔记
ST表是一种利用DP思想求解最值的倍增算法 ST表常用于解决RMQ问题,即求解区间最值问题 接下来以求最大值为例分步讲解一下ST表的建立过程: 1.定义 f[i][j]表示[i,i+2j-1]这个长度 ...
- ST表学习
啊谈不上学习了.复习一下原理留一下板子. $f\left[i,j \right]$表示以$i$为起点,区间长度为${2}^{j}$的区间最值.以最小值为例,即 $min\left(a\left [ k ...
- ST 表学习
作用:ST算法是用来求解给定区间RMQ的最值,本文以最小值为例 举例: 给出一数组A[0~5] = {5,4,6,10,1,12},则区间[2,5]之间的最值为1. 方法:ST算法分成两部分:离线预处 ...
- S-T表学习笔记
$O(nlogn)$构造$O(1)$查询真是太强辣 然而不支持修改= = ShØut! #include<iostream> #include<cstring> #includ ...
- 平衡的阵容 st表学习
模板 预处理 void rmq_isit() { ;i<=n;i++) mx[i][]=mn[i][]=a[i]; ;(<<j)<=n;j++) ;i+(<<j)- ...
- GCD(st表+二分)
GCD Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submis ...
- ST表入门学习poj3264 hdu5443 hdu5289 codeforces round #361 div2D
ST算法介绍:[转自http://blog.csdn.net/insistgogo/article/details/9929103] 作用:ST算法是用来求解给定区间RMQ的最值,本文以最小值为例 方 ...
- [学习笔记]ST表
ST表 给定一个数列$a,O(nlogn)$预处理,$O(1)$查询数列在区间$[l,r]$的最值. 本文介绍求最大值. 实现 预处理 $st[i][j]$表示$max\{a_k\}(k\in[i,i ...
- 算法学习 - ST表 - 稀疏表 - 解决RMQ问题
2017-08-26 21:44:45 writer:pprp RMQ问题就是区间最大最小值查询问题: 这个SparseTable算法构造一个表,F[i][j] 表示 区间[i, i + 2 ^ j ...
随机推荐
- ubuntu安装甲骨文最新jdk7
1.下载jdk7(我下载的是Java SE Platform(jdk) 7u51): http://www.oracle.com/technetwork/java/javase/downloads/i ...
- 学习笔记之--认识Xcode中的重要成员:lldb调试器
之前对lldb调试器了解比较少,平时主要用来打印日志和暂定时用鼠标查看属性数据以及使用p po一些简单的命令语句. 今天看了一些关于lldb的文章,顿时觉得之前对它了解太少了,原来它还有那么多的功能. ...
- Hackers top in China
黑客,英文hacker.精通计算机各类技术的计算机高手,泛指擅长IT技术的人群.计算机科学家. 最近受某机构所托搜集国内活跃黑客近况.本着客观专业,权威可信的原则参考了国内从00年到最新的黑客榜单,以 ...
- 【转】.net MVC 生命周期
对于Asp.net MVC,我对它的生命周期还是兴趣很浓,于是提出两个问题: 一个HTTP请求从IIS移交到Asp.net运行时,Asp.net MVC是在什么时机获得了控制权并对请求进行处理呢?处理 ...
- 【Hadoop系列】linux下 root用户免密码登录远程主机 ssh
SSH原理:[Hadoop系列]linux SSH原理解析 操作环境: CentOS 6.5 操作对象: 用户A主机和远程主机B 正文部分:斜体加粗代表linux指令. linux下 非root用户免 ...
- Java 不可变类
Java 不可变类 immutable object 不可变类是指这个类的实例一旦创建完成后,就不能改变其成员变量值. 如JDK内部自带的很多不可变类:Interger.Long和String等. * ...
- Synchronized的原理及自旋锁,偏向锁,轻量级锁,重量级锁的区别(摘抄和理解)
1. 自旋锁的优缺点: 自旋锁 自旋锁原理非常简单,如果持有锁的线程能在很短时间内释放锁资源,那么那些等待竞争锁的线程就不需要做内核态和用户态之间的切换进入阻塞挂起状态,它们只需要等一等(自旋),等持 ...
- db缓存设计
http://www.cnblogs.com/herm/archive/2012/11/11/2773887.html
- 一台电脑上运行两个tomcat
1.建立两个文件夹,tomcat1,tomcat2,分别在里面放入tomcat7文件(非安装版) 2.改配置 tomcat1中的配置就不用改了,直接用默认配置 tomcat2中的配置要改要,改conf ...
- css之表格,表单
一.表格 1.定义 表格由<table>标签来定义.每个表格均有若干行(由tr标签定义),每行被分割为若个单元格(由td标签定义).字母td指表格数据(table data),即数据单元格 ...