ST表的原理及其实现

ST表类似树状数组,线段树这两种算法,是一种用于解决RMQ(Range Minimum/Maximum Query,即区间最值查询)问题的离线算法

与线段树相比,预处理复杂度同为O(nlogn),查询时间上,ST表为O(1),线段树为O(nlogn)

st表的主体是一个二维数组st[i][j],表示需要查询的数组的从下标i到下标i+2^j - 1的最值,这里以最小值为例

预处理函数:

int a[];//原始输入数组
int st[][];//st表 void init(int n)
{
for (int i = ; i < n; i++)
st[i][] = a[i]; for (int j = ; ( << j) <= n; j++)
{
for (int i = ; i + ( << j) - < n; i++)
st[i][j] = min(st[i][j - ],st[i + ( << (j - ))][j - ]);
}
}

这里首先把从0~n-1的2^0部分进行覆盖,再往下继承

继承这里也很好理解,我们以一个长度为5的数组[5,1,2,3,4]为例

2^0部分覆盖过去自然是5,4,3,2,1

2^1部分的长度为4,从0一直到3,因为从下标为4开始后面只有他自己

st[0][1]是下标为0~1的最小值,自然也就是st[0][0]和st[1][0]的最值

以此往下类推我们可以得出结论:

st[i][j] = min(st[i][j - 1],st[i + 2^(j - 1))][j - 1])

到这里初始化就完成了,注意下标不要越界,如果你对为什么这么处理有困惑的话,请继续看查询

查询函数这里不太好理解

初始化时,每一个状态对应的区间长度都为2^j,由于给出的查询区间长度不一定恰好为2^j,

所以我们要引出一个定理:2^log(a)>a/2 。

因为log(a)表示小于等于a的2的最大几次方。 
比如说log(4)=2,log(5)=2,log(6)=2,log(7)=2,log(8)=3,log(9)=3……. 
那么我们要查询x到y的最小值。 
设len=y-x+1,t=log(len) 
根据上面的定理:2^t>len/2 
从位置上来说,x+2^t越过了x到y的中间! 
因为位置过了一半 
所以x到y的最小值可以表示为min(从x往后2^t的最小值,从y往前2^t的最小值) 
前面的状态表示为mn[t][x] 
设后面(从y往前2^t的最小值)的初始位置是k, 
那么k+2^t-1=y,所以k=y-2^t+1 
所以后面的状态表示为mn[t][y-2^t+1] 
所以x到y的最小值表示为min(mn[t][x],mn[t][y-2^t+1]),所以查询时间复杂度是O(1)

int search(int l, int r)
{
int k = (int)(log((double)(r - l + )) / log(2.0));
return min(st[l][k],st[r - ( << k) + ][k]);
}

示例程序:

#include <iostream>
#include <algorithm> using namespace std; int a[];//原始输入数组
int st[][];//st表 void init(int n)
{
for (int i = ; i < n; i++)
st[i][] = a[i]; for (int i = ; ( << i) <= n; i++)
{
for (int j = ; j + ( << i) - < n; j++)
st[j][i] = min(st[j][i - ],st[j + ( << (i - ))][i - ]);
}
} int search(int l, int r)
{
int k = (int)(log((double)(r - l + )) / log(2.0));
return min(st[l][k],st[r - ( << k) + ][k]);
} int main()
{
int n,m;
while (cin >> n >> m)
{
for (int i = ; i < n; i++)
cin >> a[i]; init(n); while (m--)
{
int l, r;
cin >> l >> r;
cout << search(l,r) << endl;;
}
}
return ;
}
文章内容摘抄于:
ST表的原理及其实现 - 真是啰嗦 - 博客园
ST表算法详解

ST表的更多相关文章

  1. POJ3693 Maximum repetition substring [后缀数组 ST表]

    Maximum repetition substring Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9458   Acc ...

  2. 【BZOJ-2006】超级钢琴 ST表 + 堆 (一类经典问题)

    2006: [NOI2010]超级钢琴 Time Limit: 20 Sec  Memory Limit: 552 MBSubmit: 2473  Solved: 1211[Submit][Statu ...

  3. 【BZOJ-3956】Count ST表 + 单调栈

    3956: Count Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 173  Solved: 99[Submit][Status][Discuss] ...

  4. 【BZOJ-4569】萌萌哒 ST表 + 并查集

    4569: [Scoi2016]萌萌哒 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 459  Solved: 209[Submit][Status] ...

  5. 【BZOJ-4310】跳蚤 后缀数组 + ST表 + 二分

    4310: 跳蚤 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 180  Solved: 83[Submit][Status][Discuss] De ...

  6. HDU5726 GCD(二分 + ST表)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5726 Description Give you a sequence of N(N≤100, ...

  7. Hdu 5289-Assignment 贪心,ST表

    题目: http://acm.hdu.edu.cn/showproblem.php?pid=5289 Assignment Time Limit: 4000/2000 MS (Java/Others) ...

  8. Bzoj 2006: [NOI2010]超级钢琴 堆,ST表

    2006: [NOI2010]超级钢琴 Time Limit: 20 Sec  Memory Limit: 552 MBSubmit: 2222  Solved: 1082[Submit][Statu ...

  9. ST表poj3264

      /* ST表多次查询区间最小值 设 g[j][i] 表示从第 i 个数到第 i + 2 ^ j - 1 个数之间的最小值 类似DP的说 ans[i][j]=min (ans[i][mid],ans ...

  10. COJ 1003 WZJ的数据结构(三)ST表

    WZJ的数据结构(三) 难度级别:B: 运行时间限制:3000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 试题描述 请你设计一个数据结构,完成以下功能: 给定一个大小为N的 ...

随机推荐

  1. [Linux] 搭建rsync服务端

    rsync是unix/linux下同步文件的一个高效算法,它能同步更新两处计算机的文件与目录,并适当利用查找文件中的不同块以减少数据传输. Linux守护进程的运行方式:1.独立运行(stand-al ...

  2. PhpStorm 安装ApiDebugger

    ApiDebugger,是一个开源的接口调试IntelliJ IDEA插件,具有与IDEA一致的界面,无需切换程序即可完成网络API请求,让你的code更加沉浸式. 安装 File->Setti ...

  3. mysql 查询导出(txt,csv,xls)

    1 简介 工作中产品经常会临时找我导出一些数据,导出mysql查询结果数据有几种方法,下面介绍3种. ①  mysql -u  -p  -e "sql" db > filep ...

  4. java应用程序的运行机制

    计算机高级语言类型主要有 编译型 和 解释型 两种,java是两种类型的结合. 机制:利用编译器(javac)将源文件(后缀名.java)编译成字节码文件(后缀名.class),最后利用虚拟机(jvm ...

  5. 开源ERP-成功案例分析(3)

    Odoo用户概要 关于Odoo全球的用户,我们来看一些数据: Odoo目前全球有300万使用者 Odoo系统上每天新创建的数据库超过1000个 Odoo和Word.Excel.PowerPoint一样 ...

  6. rxjava切换线程避免重复代码

    .subscribeOn(Schedulers.io()) .unsubscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThrea ...

  7. linux下的QT打包方法

    一句话很简单,一个shell脚本搞定,不跟你嘻嘻哈哈 #!/bin/shexe="ThorIceLocker"#存放你的可执行文件的名字des="/home/ninetr ...

  8. JVM远程调试功能

    有时候想调试线上的程序 可以启用远程调试功能 在本地调试远程代码. 远程JVM启用调试模式 /usr/local/jdk/bin/java -server -Xms256m -Xmx256m -XX: ...

  9. c# 多线程委托传参方式

    1.定义一个线程调用的方法函数 private void RTPServer(object _Serverip) { IPEndPoint Serverip = _Serverip as IPEndP ...

  10. MyBatis批量修改操作

    1.需求 后台管理页面,查询频道列表,需要批量修改频道的状态,批量上线和下线 2.MyBatis配置 这是mysql的配置,注意需要加上&allowMultiQueries=true配置 jd ...