前段时间做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表学习总结的更多相关文章

  1. ST表学习笔记

    ST表是一种利用DP思想求解最值的倍增算法 ST表常用于解决RMQ问题,即求解区间最值问题 接下来以求最大值为例分步讲解一下ST表的建立过程: 1.定义 f[i][j]表示[i,i+2j-1]这个长度 ...

  2. ST表学习

    啊谈不上学习了.复习一下原理留一下板子. $f\left[i,j \right]$表示以$i$为起点,区间长度为${2}^{j}$的区间最值.以最小值为例,即 $min\left(a\left [ k ...

  3. ST 表学习

    作用:ST算法是用来求解给定区间RMQ的最值,本文以最小值为例 举例: 给出一数组A[0~5] = {5,4,6,10,1,12},则区间[2,5]之间的最值为1. 方法:ST算法分成两部分:离线预处 ...

  4. S-T表学习笔记

    $O(nlogn)$构造$O(1)$查询真是太强辣 然而不支持修改= = ShØut! #include<iostream> #include<cstring> #includ ...

  5. 平衡的阵容 st表学习

    模板 预处理 void rmq_isit() { ;i<=n;i++) mx[i][]=mn[i][]=a[i]; ;(<<j)<=n;j++) ;i+(<<j)- ...

  6. GCD(st表+二分)

    GCD Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submis ...

  7. ST表入门学习poj3264 hdu5443 hdu5289 codeforces round #361 div2D

    ST算法介绍:[转自http://blog.csdn.net/insistgogo/article/details/9929103] 作用:ST算法是用来求解给定区间RMQ的最值,本文以最小值为例 方 ...

  8. [学习笔记]ST表

    ST表 给定一个数列$a,O(nlogn)$预处理,$O(1)$查询数列在区间$[l,r]$的最值. 本文介绍求最大值. 实现 预处理 $st[i][j]$表示$max\{a_k\}(k\in[i,i ...

  9. 算法学习 - ST表 - 稀疏表 - 解决RMQ问题

    2017-08-26 21:44:45 writer:pprp RMQ问题就是区间最大最小值查询问题: 这个SparseTable算法构造一个表,F[i][j] 表示 区间[i, i + 2 ^ j ...

随机推荐

  1. 【转】HttpURLConnection用法详解

    原文链接:http://www.blogjava.net/supercrsky/articles/247449.html 针对JDK中的URLConnection连接Servlet的问题,网上有虽然有 ...

  2. 使用Charles为Android设备抓取https请求的包

    之前开发的Android APP使用的都是http请求,之后改成了https,就出现了以下情况,无法正常读取抓取的内容 找了好多资料说法大概差不多,照着弄,结果出现如下情况,后来发现这种情况其实是手机 ...

  3. [转]Supporting OData Query Options in ASP.NET Web API 2

    本文转自:https://docs.microsoft.com/en-us/aspnet/web-api/overview/odata-support-in-aspnet-web-api/suppor ...

  4. IDEA创建一个Spring MVC 框架Java Web项目,Gradle构建

    注:此篇有些细节没写出,此文主要写重要的环节和需要注意的地方,轻喷 新建项目 选择Gradle , 勾选java 和 web.之后就是设定项目路径和名称,这里就不啰嗦了. build.gradle文件 ...

  5. ssm架构添加maven、shiro、lucene、ueditor、druid支持

    1.pom.xml文件配置: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http: ...

  6. redis(2)数据类型

    一.数据类型 redis的数据结构是key-value的键值对的形式,但是它和传统String-String的键值对形式不一样,它的value不仅仅是string类型,而是有着丰富的数据类型,如: 1 ...

  7. Java基础(10)——小结与填坑

    前面都写了9篇啦,虽然断断续续发了半个月,写着写着会发现每篇中都有些比较重要的地方没有讲到~这篇还是需要填一填目前我已发现的坑了~ 一. 小结 Java编译命令 javac.运行命令java java ...

  8. 微信公众号开发《一》OAuth2.0网页授权认证获取用户的详细信息,实现自动登陆

    原创声明:本文为本人原创作品,绝非他处转账,转载请联系博主 从接触公众号到现在,开发维护了2个公众号,开发过程中遇到很多问题,现在把部分模块功能在这备案一下,做个总结也希望能给其他人帮助 工欲善其事, ...

  9. mysql 的用法

    SELECT CASEWHEN    //当count(userId) = 0的时候 让其为null 不然报警告 // count(DISTINCT userId) 不用处理 count(userId ...

  10. 小白学flask之路由,反向路由,路由参数

    # -*- coding: utf-8 -*- from flask import Flask, request, url_for app = Flask(__name__) @app.route(& ...