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 ...
随机推荐
- win10中xshell的ssh链接virtualBox中的centos7
win10下virtualbox中centos7.3与主机通过xshell的ssh建立连接的方法 2017-02-19 01:29 版权声明:本文为博主原创文章,未经博主允许不得转载. 最近 ...
- Environment.Exit(0) 、Application.Exit() 、this.Close() 、this.Dispose()的区别
Application.Exit:通知winform消息循环退出.程序会等待所有的前台线程终止后才能真正退出.是一种强行退出方式,就像 Win32 的 PostQuitMessage().它意味着放弃 ...
- yum -y update 报错:GPG key retrieval failed: [Errno 14] Could not open/read file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5
用的是centos6.5的镜像,yum源太老了,修改了之后想更新一下: yum -y update 执行报错: warning: rpmts_HdrFromFdno: Header V3 RSA/SH ...
- ios audio不能自动播放
今天做了一个简单的落地页项目,就是类似于手机微信上经常看到的滑动效果.因为公司要求需要自己开发,所以我就用swiper+swiper.animate开发,开发速度很快,只不过最后音乐哪里出现了一点小b ...
- Silverlight & Blend动画设计系列七:模糊效果(BlurEffect)与阴影效果(DropShadowEffect)
模糊效果(BlurEffect)与阴影效果(DropShadowEffect)是两个非常实用和常用的两个特效,比如在开发相册中,可以对照片的缩略图添加模糊效果,在放大照片的过程中动态改变照片的大小和模 ...
- Linux From Scratch(从零开始构建Linux系统,简称LFS)(一)
一. 准备工作 1. 需要一个Linux宿主系统,例如早先版本的 LFS,Ubuntu/Fedora,SuSE 或者是在你的架构上可以运行的其它发行版 如果想实现Win7与Linux双系统,可参考我的 ...
- hdu 3535 (最少1,最多1,任意)(背包混合)(好题)
http://blog.csdn.net/yan_____/article/details/8530833 这个问题一开始我用滚动,没有做出来,可能要需要先预处理排序才行,后来看了别人的方法,开始用二 ...
- COGS2216 你猜是不是KMP
第一道自己写的FFT...... 不知为啥这题在网上找不到题解......真是麻烦,害得我推了半天...... 还是写个简要题解吧...... 首先把S和T拆成序列,a~z分别对应成1~26,?是0, ...
- HADOOP背景介绍
1. HADOOP背景介绍 1.1 什么是HADOOP 1. HADOOP是apache旗下的一套开源软件平台 2. HADOOP提供的功能:利用服务器集群,根据用户的自定义业务逻辑,对海量数据进行分 ...
- [小北De编程手记] : Lesson 05 - Selenium For C# 之 API 下
上一篇,我们介绍了一些Selenium WebDriver相关的API,下面我们就接着上一篇继续介绍Selenium常用的API,这一篇的内容主要涉及到以下话题: Selenium API:复杂事件处 ...