【引子】RMQ (Range Minimum/Maximum Query)问题:

对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中下标在i,j里的最小(大)值,也就是说,RMQ问题是指求区间最值的问题。

{方法}

           1、朴素(即搜索),O(n)-O(qn) online。
           2、线段树,O(n)-O(qlogn) online。
    3、ST(实质是动态规划),O(nlogn)-O(q) online。
        ST算法(Sparse Table),以求最大值为例,设d[i,j]表示[i,i+2^j-1]这个区间内的最大值,那么在询问到[a,b]区间的最大值时答案就是 max(d[a,k], d[b-2^k+1,k]),        其中k是满足2^k<=b-a+1(即长度)的最大的k,即k=[ln(b-a+1)/ln(2)]。
        d的求法可以用动态规划,d[i, j]=max(d[i, j-1],d[i+2^(j-1), j-1])。
    4、RMQ标准算法:先规约成LCA(Lowest Common Ancestor),再规约成约束RMQ,O(n)-O(q) online。
        首先根据原数列,建立笛卡尔树,从而将问题在线性时间内规约为LCA问题。LCA问题可以在线性时间内规约为约束RMQ,也就是数列中任意两个相邻的数的差都是+1或-1        的RMQ问题。约束RMQ有O(n)-O(1)的在线解法,故整个算法的时间复杂度为O(n)-O(1)。

【例】给定数组,询问区间最小值。(无修改)
    (数据范围不用线段树)

【解】可以写一个线段树,但是预处理和查询的复杂度都是O(logn),存心的话可以给你卡掉。

  所以采用ST算法,它可以做到O(nlogn)的预处理,O(1)地回答每个询问

  f[i][j]表示数组p从位置i开始到位置i+2^j-1的最小值
  f[i][j]=min(f[i+(1<<(j-1))][j-1],f[i][j-1]);f[i][0]=p[i].
  求a~b的最小值,就是找出比b-a+1小的最大的二的幂次k
  有ans=min(f[a][k],f[b-(1<<k)+1][k])

【原理】

nlogn预处理出Min[][]和Max[][],查询的时候O(1)查询。

Max[j][i]或Min[j][i]代表,从j的位置开始,长度为2^i的子段中的最大值或最小值。

然后预处理的时候递推。

询问的时候先算出[l,r]的长度的2的对数,然后取出答案即可

是一种优秀的存取方法。

【实现】(以最大值为例):
    首先是预处理,用一个DP解决。设a[i]是要求区间最值的数列,f[i,j]表示从第i个数起连续2^j个数中的最大值。例如数列3 2 4 5
6 8 1 2 9 7
,f[1,0]表示第1个数起,长度为2^0=1的最大值,其实就是3这个数。
f[1,2]=5,f[1,3]=8,f[2,0]=2,f[2,1]=4……从这里可以看出f[i,0]其实就等于a[i]。这样,Dp的状态、初值都
已经有了,剩下的就是状态转移方程。我们把f[i,j]平均分成两段(因为f[i,j]一定是偶数个数字),从i到i+2^(j-1)-1为一
段,i+2^(j-1)到i+2^j-1为一段(长度都为2^(j-1))。用上例说明,当i=1,j=3时就是3,2,4,5

6,8,1,2这两段。f[i,j]就是这两段的最大值中的最大值。于是我们得到了动规方程F[i,j]=max(F[i,j-1],F[i+2^(j-
i),j-1]).
     
  
 接下来是得出最值,也许你想不到计算出f[i,j]有什么用处,想计算max还是要O(logn),甚至O(n)。但有一个很好的办法,做到了
O(1)。还是分开来。如在上例中我们要求区间[2,8]的最大值,就要把它分成[2,5]和[5,8]两个区间,因为这两个区间的最大值我们可以直接由
f[2,2]和f[5,2]得到。扩展到一般情况,就是把区间[l,r]分成两个长度为2^n的区间(保证有f[i,j]对应)

【模板代码】

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstdlib>
#include<iomanip>
#include<cassert>
#include<climits>
#define maxn 100001
#define F(i,j,k) for(int i=j;i<=k;i++)
#define M(a,b) memset(a,b,sizeof(a))
#define FF(i,j,k) for(int i=j;i>=k;i--)
#define inf 0x7fffffff
#define maxm 21
using namespace std;
int read(){
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
int fm[maxn][maxm],fi[maxn][maxm],p[maxn];
int n,q;
inline int init()
{
cin>>n>>q;
F(i,,n){
cin>>p[i];
}
F(i,,n){
fm[i][]=fi[i][]=p[i];
}
int m=floor((int)(log10((double)n)/log10((double))));
F(j,,m)F(i,,n){
fm[i][j]=max(fm[i+(<<(j-))][j-],fm[i][j-]);
fi[i][j]=min(fi[i+(<<(j-))][j-],fi[i][j-]);
}
}
inline int stmax(int a,int b)
{
int m=floor((int)(log10((double)(b-a+))/log10((double))));
return max(fm[a][m],fm[b-(<<m)+][m]);
}
inline int stmin(int a,int b)
{
int m=floor((int)(log10((double)(b-a+))/log10((double))));
return min(fi[a][m],fi[b-(<<m)+][m]);
}
int main()
{
std::ios::sync_with_stdio(false);//cout<<setiosflags(ios::fixed)<<setprecision(1)<<y;
// freopen("data.in","r",stdin);
// freopen("data.out","w",stdout);
init();int c,d;
while(q--)
{
int a,b;
cin>>a>>b;
if(a>b) swap(a,b);
c=stmax(a,b);
d=stmin(a,b);
cout<<c<<endl<<d<<endl;
}
return ;
}

ST

学习笔记 ST算法的更多相关文章

  1. [ML学习笔记] XGBoost算法

    [ML学习笔记] XGBoost算法 回归树 决策树可用于分类和回归,分类的结果是离散值(类别),回归的结果是连续值(数值),但本质都是特征(feature)到结果/标签(label)之间的映射. 这 ...

  2. 学习笔记 - Manacher算法

    Manacher算法 - 学习笔记 是从最近Codeforces的一场比赛了解到这个算法的~ 非常新奇,毕竟是第一次听说 \(O(n)\) 的回文串算法 我在 vjudge 上开了一个[练习],有兴趣 ...

  3. 学习笔记——EM算法

    EM算法是一种迭代算法,用于含有隐变量(hidden variable)的概率模型参数的极大似然估计,或极大后验概率估计.EM算法的每次迭代由两步组成:E步,求期望(expectation):M步,求 ...

  4. 数据挖掘学习笔记--AdaBoost算法(一)

    声明: 这篇笔记是自己对AdaBoost原理的一些理解,如果有错,还望指正,俯谢- 背景: AdaBoost算法,这个算法思路简单,但是论文真是各种晦涩啊-,以下是自己看了A Short Introd ...

  5. 学习笔记-KMP算法

    按照学习计划和TimeMachine学长的推荐,学习了一下KMP算法. 昨晚晚自习下课前粗略的看了看,发现根本理解不了高端的next数组啊有木有,不过好在在今天系统的学习了之后感觉是有很大提升的了,起 ...

  6. Java学习笔记——排序算法之快速排序

    会当凌绝顶,一览众山小. --望岳 如果说有哪个排序算法不能不会,那就是快速排序(Quick Sort)了 快速排序简单而高效,是最适合学习的进阶排序算法. 直接上代码: public class Q ...

  7. Java学习笔记——排序算法之进阶排序(堆排序与分治并归排序)

    春蚕到死丝方尽,蜡炬成灰泪始干 --无题 这里介绍两个比较难的算法: 1.堆排序 2.分治并归排序 先说堆. 这里请大家先自行了解完全二叉树的数据结构. 堆是完全二叉树.大顶堆是在堆中,任意双亲值都大 ...

  8. Java学习笔记——排序算法之希尔排序(Shell Sort)

    落日楼头,断鸿声里,江南游子.把吴钩看了,栏杆拍遍,无人会,登临意. --水龙吟·登建康赏心亭 希尔算法是希尔(D.L.Shell)于1959年提出的一种排序算法.是第一个时间复杂度突破O(n²)的算 ...

  9. 学习笔记——SM2算法原理及实现

    RSA算法的危机在于其存在亚指数算法,对ECC算法而言一般没有亚指数攻击算法 SM2椭圆曲线公钥密码算法:我国自主知识产权的商用密码算法,是ECC(Elliptic Curve Cryptosyste ...

随机推荐

  1. [BZOJ4942][Noi2017]整数 线段树+压位

    用线段树来模拟加减法过程,维护连续一段中是否全为0/1. 因为数字很大,我们60位压一位来处理. #include<iostream> #include<cstring> #i ...

  2. Java Programs

    Java Programs Fibonacci series in Java public class FibonacciExample { public static void main(Strin ...

  3. XML DOM(Document Object Model)

    1.XML DOM 是用于获取.更改.添加或删除 XML 元素的标准.2.节点(XML 文档中的每个成分都是一个节点):        整个文档是一个文档节点:        每个XML元素是一个元素 ...

  4. 堆优化Dijkstra计算最短路+路径计数

    今天考试的时候遇到了一道题需要路径计数,然而蒟蒻从来没有做过,所以在考场上真的一脸懵逼.然后出题人NaVi_Awson说明天考试还会卡SPFA,吓得我赶紧又来学一波堆优化的Dijkstra(之前只会S ...

  5. pycharm的安装教程及大坑

    在根据网上的教程创建新工程后,发现不能调用第三方库,网上大多给的是print('hello world'),己适python解释器用的pycharm默认的也不能发现错误.后来浏览了一篇文章才恍然大悟, ...

  6. angular4 使用window事件

    Angular使用window对象中的事件最好不要像使用jQuery那样使用 如下: 注:写事件直接绑定到window对象上了,组件销毁时这个事件没有解绑 可以使用剪头函数不用声明that 注:这样写 ...

  7. properties文件乱码问题 eclipse

    java最常用的开发工具eclipse里面的properties配置文件里面打开中文是乱码的,解决方式很简单. 将default encoding 设置为utf-8即可. 效果: 漂亮!!!

  8. 【数据结构】Trie树

    数据结构--Trie树 概念 Trie树,又称字典树.前缀树,是一种树形结构,是一种哈希树的变种.典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计 ...

  9. Tornado(一)

    Tornado 特点 Tornado是一个用Python写的相对简单的.不设障碍的Web服务器架构,用以处理上万的同时的连接口,让实时的Web服务通畅起来.虽然跟现在的一些用Python写的Web架构 ...

  10. POJ 3553 Light Switching Game 博弈论 nim积 sg函数

    http://poj.org/problem?id=3533 变成三维的nim积..前面hdu那个算二维nim积的题的函数都不用改,多nim积一次就过了...longlong似乎不必要但是还是加上了 ...