Sparse Table算法+poj3264(Balanced line up)题解----倍增思想
2016-07-19 10:55
609 查看
题意就是求一段区间的最大值和最小值之差(RMQ问题)。由于查询量大,考虑使用st表(空间复杂度(O(nlogn)),初始化复杂度(O(nlogn)),查询复杂度(O(1))!!!)
Sparse Table算法,简称ST算法,可以用来求解RMQ(区间最值查询)问题。
RMQ问题的形式一般是:存在一个大数组,要求对于给定的起点和终点,迅速回答出这段区间的最大值或最小值。
最朴素的方式是扫描起点到终点的所有数,维护其中的最值,这样的复杂度是O(n^2)的,速度太慢。ST算法是使用的是类似于二分的动态规划思想,其复杂度是O(nlogn),因此查询速度非常快。
ST算法的执行过程(以求最大值为例):
1、初始化:
设原数组为x
。
先开一个数组dp
[33]。其中dp[i][j]表示的是从下标为i的元素开始,到下标为(i + 2^j - 1)的元素为止,这些元素中的最大值。对于整型而言,其值不会超过2^32,因此第二维大小为33已经足够。
因此dp[i][0]表示的是元素本身,因此可以初始化为dp[i][0] = x[i]。
对于其他的dp[i][j],可以采用动态规划的方式求出,递推式为dp[i][j] = max(dp[i][j - 1], dp[i + 2 ^ (j - 1)][j - 1]),其实就是把一段区间切成两段大小相等的区间,当前区间的最大值就是两个子区间的最大值中的较大者。
初始化的复杂度为O(nlogn)。
2、求解:
对于给定的起点srt及终点end,可以得出区间大小为range = end - srt + 1。
因此可以找到一个整数k = floor(log2(range))。这样区间就可以被划分为子区间[srt, srt + (2 ^ k) - 1],子区间[end - (2 ^ k) + 1, end]。这两个很可能会有重叠,重合显然不影响求解(不妨举几个数据模拟一下)。因此对于srt和end,可以得到解为res = max(dp[srt][k], dp[end - (2 ^ k) + 1][k])。
求解的复杂度为O(1)。
显然可以使用二进制来计算k,速度会相对快一些。
具体方法是:
k = 0, p = 2, range = end - srt + 1;
while (p <= range)
{
k++;
p <<= 1;
}
Sparse Table算法,简称ST算法,可以用来求解RMQ(区间最值查询)问题。
RMQ问题的形式一般是:存在一个大数组,要求对于给定的起点和终点,迅速回答出这段区间的最大值或最小值。
最朴素的方式是扫描起点到终点的所有数,维护其中的最值,这样的复杂度是O(n^2)的,速度太慢。ST算法是使用的是类似于二分的动态规划思想,其复杂度是O(nlogn),因此查询速度非常快。
ST算法的执行过程(以求最大值为例):
1、初始化:
设原数组为x
。
先开一个数组dp
[33]。其中dp[i][j]表示的是从下标为i的元素开始,到下标为(i + 2^j - 1)的元素为止,这些元素中的最大值。对于整型而言,其值不会超过2^32,因此第二维大小为33已经足够。
因此dp[i][0]表示的是元素本身,因此可以初始化为dp[i][0] = x[i]。
对于其他的dp[i][j],可以采用动态规划的方式求出,递推式为dp[i][j] = max(dp[i][j - 1], dp[i + 2 ^ (j - 1)][j - 1]),其实就是把一段区间切成两段大小相等的区间,当前区间的最大值就是两个子区间的最大值中的较大者。
初始化的复杂度为O(nlogn)。
2、求解:
对于给定的起点srt及终点end,可以得出区间大小为range = end - srt + 1。
因此可以找到一个整数k = floor(log2(range))。这样区间就可以被划分为子区间[srt, srt + (2 ^ k) - 1],子区间[end - (2 ^ k) + 1, end]。这两个很可能会有重叠,重合显然不影响求解(不妨举几个数据模拟一下)。因此对于srt和end,可以得到解为res = max(dp[srt][k], dp[end - (2 ^ k) + 1][k])。
求解的复杂度为O(1)。
显然可以使用二进制来计算k,速度会相对快一些。
具体方法是:
k = 0, p = 2, range = end - srt + 1;
while (p <= range)
{
k++;
p <<= 1;
}
//st表初始化方法 for(int i=1;i<=n;i++) {scanf("%d",arr+i); fx[i][0]=fn[i][0]=arr[i]; } for(int d=1;(1<<d)<=n;d++) for(int i=1;i<=n;i++) if(i+(1<<(d-1))<=n)//这里要好好想一下为什么 fx[i][d]=max(fx[i][d-1],fx[i+(1<<(d-1))][d-1] ), fn[i][d]=min(fn[i][d-1],fn[i+(1<<(d-1))][d-1] ); else fx[i][d]=fx[i][d-1],fn[i][d]=fn[i][d-1];
#include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> #define ms(X) memset(X,0,sizeof(X)) using namespace std; typedef long long LL; int arr[50005],fx[50005][34],fn[50005][34]; int main() { int n,q; scanf("%d %d",&n,&q); for(int i=1;i<=n;i++) {scanf("%d",arr+i); fx[i][0]=fn[i][0]=arr[i]; } for(int d=1;(1<<d)<=n;d++) for(int i=1;i<=n;i++) if(i+(1<<(d-1))<=n) fx[i][d]=max(fx[i][d-1],fx[i+(1<<(d-1))][d-1] ), fn[i][d]=min(fn[i][d-1],fn[i+(1<<(d-1))][d-1] ); else fx[i][d]=fx[i][d-1],fn[i][d]=fn[i][d-1]; while(q--) { int tmin,tmax,a,b; scanf("%d %d",&a,&b); int rang=b-a+1; int k=0,p=2; while(p<=rang ) {k++;p<<=1;} tmin=min(fn[a][k],fn[b-(1<<k)+1][k]); tmax=max(fx[a][k],fx[b-(1<<k)+1][k]); printf("%d\n",tmax-tmin); } return 0; }
相关文章推荐
- 初学ACM - 组合数学基础题目PKU 1833
- POJ ACM 1001
- POJ ACM 1002
- 1611:The Suspects
- POJ1089 区间合并
- POJ 2159 Ancient Cipher
- POJ 2635 The Embarrassed Cryptographe
- POJ 3292 Semi-prime H-numbers
- POJ 2773 HAPPY 2006
- POJ 3090 Visible Lattice Points
- POJ-2409-Let it Bead&&NYOJ-280-LK的项链
- POJ-1695-Magazine Delivery-dp
- POJ1523 SPF dfs
- POJ-1001 求高精度幂-大数乘法系列
- POJ-1003 Hangover
- POJ-1004 Financial Management
- [数论]poj2635__The Embarrassed Cryptographer
- [二分图匹配]poj2446__Chessboard
- POJ1050 最大子矩阵和
- 用单调栈解决最大连续矩形面积问题