前段时间做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代码:

  1. #include <stdio.h>
  2. #include <math.h>
  3. #include <algorithm>
  4. #include <iostream>
  5. using namespace std;
  6.  
  7. const int maxn=;
  8.  
  9. int stmax[maxn][];
  10. int stmin[maxn][];
  11.  
  12. int n,m;
  13.  
  14. void ST() {
  15. int k=int(log(1.0*n)/log(2.0));
  16. for(int j=; j<=k; j++) {
  17. for(int i=; i+(<<j)-<=n; i++) {
  18. stmax[i][j]=max(stmax[i][j-],stmax[i+(<<(j-))][j-]);
  19. stmin[i][j]=min(stmin[i][j-],stmin[i+(<<(j-))][j-]);
  20. }
  21. }
  22. }
  23.  
  24. int qmax(int l,int r) {
  25. int k=int(log(1.0*(r-l+))/log(2.0));
  26. return max(stmax[l][k],stmax[r-(<<k)+][k]);
  27. }
  28.  
  29. int qmin(int l,int r) {
  30. int k=int(log(1.0*(r-l+))/log(2.0));
  31. return min(stmin[l][k],stmin[r-(<<k)+][k]);
  32. }
  33.  
  34. int main() {
  35. scanf("%d %d",&n,&m);
  36. for(int i=; i<=n; i++) {
  37. int temp;
  38. scanf("%d",&temp);
  39. stmax[i][]=stmin[i][]=temp;
  40. }
  41. ST();
  42. for(int i=; i<m; i++) {
  43. int a,b;
  44. scanf("%d %d",&a,&b);
  45. int ans=qmax(a,b)-qmin(a,b);
  46. printf("%d\n",ans);
  47. }
  48.  
  49. return ;
  50. }

之后的第二个样题是HDU 5726,是求一个区间的最大公约数,并且同时输出有多少个区间和这个区间的最大公约数相同。因为这个题目需要知道有多少个区间的最大公约数和那个区间相同,考虑到规模很明显不能现算,所以用ST表是一种不错的选择,这个题目同时还涉及到了gcd的不会递增的性质和二分查找,大家只需要关注一下ST表的建立和查询那部分就好了。

AC代码:

  1. #include <stdio.h>
  2. #include <math.h>
  3. #include <map>
  4. #include <string.h>
  5. #include <iostream>
  6. using namespace std;
  7. const int maxn=;
  8. map<int,long long> mp;
  9.  
  10. int gcd(int a,int b){
  11. if(b==){
  12. return a;
  13. }
  14. return gcd(b,a%b);
  15. }
  16.  
  17. int n,m;
  18. int st[maxn][];
  19.  
  20. void ST(){
  21. int k=int(log(1.0*n)/log(2.0));
  22. for(int j=;j<=k;j++){
  23. for(int i=;i+(<<j)<=n;i++){
  24. st[i][j]=gcd(st[i][j-],st[i+(<<(j-))][j-]);
  25. }
  26. }
  27. }
  28.  
  29. int query(int l,int r){
  30. int k=int(log(1.0*(r-l+))/log(2.0));
  31. return gcd(st[r-(<<k)+][k],st[l][k]);
  32. }
  33.  
  34. int main(){
  35. int T;
  36. scanf("%d",&T);
  37. for(int cas=;cas<=T;cas++){
  38. memset(st,,sizeof(st));
  39. mp.clear();
  40. scanf("%d",&n);
  41. for(int i=;i<n;i++){
  42. scanf("%d",&st[i][]);
  43. }
  44. ST();
  45. for(int i=;i<n;i++)
  46. {
  47. int t,ll=i;
  48. while(ll<n)
  49. {
  50. t=query(i,ll);
  51. int l=ll,r=n-;
  52. while(l<r)
  53. {
  54. int mid=(l+r+)>>;
  55. if(query(i,mid)>=t)l=mid;
  56. else r=mid-;
  57. }
  58. mp[t]+=l-ll+;
  59. ll=l+;
  60. }
  61. }
  62. int q;
  63. scanf("%d",&q);
  64. printf("Case #%d:\n",cas);
  65. while(q--)
  66. {
  67. int l,r;
  68. scanf("%d%d",&l,&r);
  69. l--,r--;
  70. printf("%d %I64d\n",query(l,r),mp[query(l,r)]);
  71. }
  72.  
  73. }
  74. return ;
  75. }

    

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. jmeter(6)——集合点与检查点

    集合点 1.概念 集合点:我们所说的并发不会是真正的并发, 集合点可以理解成,所有的用户在进行某一操作时在同一时间点一起执行,比如:抢票或者促销抢购,集合点可以帮助我们使并发更加有效可控 2.位置 位 ...

  2. cesium运行环境搭建

    cesiumjs是什么 一个世界级3D地球仪和地图的开源JavaScript库. 1.安装node.js 环境 1)下载node.js 官网:https://nodejs.org/en/ 下载完成后双 ...

  3. MySQL触发器基本介绍

    基本简介: 1.触发器可以让你在执行insert,update,delete语句的时候,执行一些特定的操作.并且可以在MySQL中指定是在sql语句执行前触发还是执行后触发. 2.触发器没有返回值. ...

  4. 创建WPF用户控件

    wpf用户自定义控件和winform创建方法类似,这里先纠正一个误区,就是有很多人也是添加,然后新建,然后是新建用户控件库,但是为什么编译好生成后Debug目录下还是只有exe文件而没有dll文件呢? ...

  5. 使用union合并查询

    语法: select …..from 表1 union select ……from 表2 2. 合并查询的特点 ① 合并的表中的列的个数.数据类型必须相同或向兼容. ② union默认去掉重复值,如果 ...

  6. 使用Having子句

    Having 子句与where子句的功能类似,都是对行进行筛选.但是,where搜索条件是在分组操作之前对记录进行筛选,然后再由group BY 对筛选后符合条件的行进行分组:而Having搜索条件则 ...

  7. springboot1.5.10兼容高版本6.1.1elasticsearch

    1.引入依赖 <dependency> <groupId>org.elasticsearch</groupId> <artifactId>elastic ...

  8. javaweb带父标签的自定义标签

    1.完整的示例代码:要实现的功能是父标签中有name属性,子标签将父标签的name属性值打印到jsp页面上. 1.1 父类和子类的标签处理器类 testParentTag.java package c ...

  9. Android源码下编译APK步骤

    1.进入android源码目录下的build下执行:source envsetup.sh 后继续在该路径下执行lunch. 2.编写完成工程 3.编写Android.mk文件,放入工程目录下     ...

  10. unity3d之控制人物转向移动并播放动画

    tip:transition 勾选Has Exit Time B动画播放完毕后就可以自己返回A不用代码控制.因为想做一个小人静止时 隔两秒会摆动小手的特效. 附上代码参考: using UnityEn ...