学习笔记 ST算法
【引子】RMQ (Range Minimum/Maximum Query)问题:
对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中下标在i,j里的最小(大)值,也就是说,RMQ问题是指求区间最值的问题。
{方法}
【例】给定数组,询问区间最小值。(无修改)
(数据范围不用线段树)
【解】可以写一个线段树,但是预处理和查询的复杂度都是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算法的更多相关文章
- [ML学习笔记] XGBoost算法
[ML学习笔记] XGBoost算法 回归树 决策树可用于分类和回归,分类的结果是离散值(类别),回归的结果是连续值(数值),但本质都是特征(feature)到结果/标签(label)之间的映射. 这 ...
- 学习笔记 - Manacher算法
Manacher算法 - 学习笔记 是从最近Codeforces的一场比赛了解到这个算法的~ 非常新奇,毕竟是第一次听说 \(O(n)\) 的回文串算法 我在 vjudge 上开了一个[练习],有兴趣 ...
- 学习笔记——EM算法
EM算法是一种迭代算法,用于含有隐变量(hidden variable)的概率模型参数的极大似然估计,或极大后验概率估计.EM算法的每次迭代由两步组成:E步,求期望(expectation):M步,求 ...
- 数据挖掘学习笔记--AdaBoost算法(一)
声明: 这篇笔记是自己对AdaBoost原理的一些理解,如果有错,还望指正,俯谢- 背景: AdaBoost算法,这个算法思路简单,但是论文真是各种晦涩啊-,以下是自己看了A Short Introd ...
- 学习笔记-KMP算法
按照学习计划和TimeMachine学长的推荐,学习了一下KMP算法. 昨晚晚自习下课前粗略的看了看,发现根本理解不了高端的next数组啊有木有,不过好在在今天系统的学习了之后感觉是有很大提升的了,起 ...
- Java学习笔记——排序算法之快速排序
会当凌绝顶,一览众山小. --望岳 如果说有哪个排序算法不能不会,那就是快速排序(Quick Sort)了 快速排序简单而高效,是最适合学习的进阶排序算法. 直接上代码: public class Q ...
- Java学习笔记——排序算法之进阶排序(堆排序与分治并归排序)
春蚕到死丝方尽,蜡炬成灰泪始干 --无题 这里介绍两个比较难的算法: 1.堆排序 2.分治并归排序 先说堆. 这里请大家先自行了解完全二叉树的数据结构. 堆是完全二叉树.大顶堆是在堆中,任意双亲值都大 ...
- Java学习笔记——排序算法之希尔排序(Shell Sort)
落日楼头,断鸿声里,江南游子.把吴钩看了,栏杆拍遍,无人会,登临意. --水龙吟·登建康赏心亭 希尔算法是希尔(D.L.Shell)于1959年提出的一种排序算法.是第一个时间复杂度突破O(n²)的算 ...
- 学习笔记——SM2算法原理及实现
RSA算法的危机在于其存在亚指数算法,对ECC算法而言一般没有亚指数攻击算法 SM2椭圆曲线公钥密码算法:我国自主知识产权的商用密码算法,是ECC(Elliptic Curve Cryptosyste ...
随机推荐
- C# 6.0 新特性 (一)
概述 尽管 C# 6.0 尚未完成,但现在这些功能正处于接近完成的关键时刻.自 2014 年 5 月发布文章“C# 6.0 语言预览版”(msdn.microsoft.com/magazine/dn6 ...
- <<Javascript Patterns>>阅读笔记 -- 第2章 基本技巧(二)
关于for-in循环 循环数据时, 强烈不推荐使用for-in循环.因为当Array对象被扩展后, 再用for-in循环遍历数据会导致逻辑上的错误, 举例说明: var arr = ['a', 'b' ...
- <<Javascript Patterns>>阅读笔记 -- 第2章 基本技巧(一)
第一次写这种东西, 有些生涩和蹩脚, 也是为了自己在表达或是总结方面有所提高, 同时为看过的东西留个痕迹, 以便日后查阅. 有错误或是不妥的地方, 还望各位指正, 谢谢! 第1章 简介 本章主要介绍了 ...
- Codeforces Round #222 (Div. 1) 博弈 + dp
一般这种要倒着来. #include<bits/stdc++.h> #define LL long long #define fi first #define se second #def ...
- 解析kubernetes架构
一. 简介: kubernetes是一个开源的容器管理工具,是基于GO语言开实现的,轻量级和便携式的应用,可以把kubernetes cluster在linux主机上部署.管理和扩容docker容器的 ...
- LeetCode 628. 三个数的最大乘积
题目描述 LeetCode 628. 三个数的最大乘积 给定一个整型数组,在数组中找出由三个数组成的最大乘积,并输出这个乘积. 示例1 输入: [1,2,3] 输出: 6 示例2 输入: [1,2,3 ...
- python3 怎么统计英文文档常用词?(附解释)
# coding: utf-8 # In[32]: #import requests #from bs4 import BeautifulSoup #res = requests.get(" ...
- ref和out的用法和区别。
关于ref和out的用法和区别在网上已经有很多的解释,这里只不过是写下对于我而说比较容易理解的解释. ref和out都可以用来在函数中返回数据,类似于c++中指针. 参数 Ref Out 是否一定需要 ...
- 【BZOJ 3727】 3727: PA2014 Final Zadanie (递推)
3727: PA2014 Final Zadanie Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 279 Solved: 121 Descript ...
- 【BZOJ 2436】 2436: [Noi2011]Noi嘉年华 (区间DP)
2436: [Noi2011]Noi嘉年华 Description NOI2011 在吉林大学开始啦!为了迎接来自全国各地最优秀的信息学选手,吉林大学决定举办两场盛大的 NOI 嘉年华活动,分在两个不 ...