ST算法(倍增)

作用:

ST算法是用来对任意一个数组,求其任以(l~r)区间内的最大值(最小值也可以)。

题解:

引出:

首先遇到这一类题,我们可以暴力查找,但是这种方法如果询问多次,直接让您原地起飞,显然我们机智的"前人"是不能忍的,于是牛逼的ST算法出现了。
其方法主要是以 O ( N l o g N ) O(N log_{} N) O(NlogN)的时间,最后以 O ( 1 ) O(1) O(1)时间回答。

题解:

设f[i][j]表示子区间 ( i , i + 2 j − 1 ) (i,i + 2^{j} - 1) i,i+2j1中的最大值。我们可以倍增区间长度,那么则有 f [ i ] [ j ] = m a x ( f [ i ] [ j − 1 ] , f [ i + ( 1 < < ( j − 1 ) ) ] [ j − 1 ] ) f[i][j] = max(f[i][j - 1], f[i + (1<<(j - 1))][j-1]) f[i][j]=max(f[i][j1],f[i+(1<<(j1))][j1]),即是 ( i — — i + 2 j − 1 ) (i——i + 2^{j} - 1) ii+2j1区间最大值=将长度为 2 j 2^{j} 2j分成两半: ( i — — i + 2 j − 1 ) (i——i+2^{j - 1}) ii+2j1 ( i + 2 j − 1 (i+2^{j - 1} (i+2j1—— i i i + 2 j 2^{j} 2j - 1)中间取最大。可以想成递推的方式吧。

初始化:
f[i][0]即是指 i i i~ i i i最大值=a[i];

输出:
假设我们需要查询区间[l,r]中的最小值,令 k = l o g 2 ( r − l + 1 ) k=log2(r−l+1) k=log2(rl+1),则最小值为 m a x ( f [ l ] [ k ] , f [ r − ( 1 < < k ) + 1 ] [ k ] ) max(f[l][k], f[r - (1 << k) + 1][k]) max(f[l][k],f[r(1<<k)+1][k])
证明:
更据前面分析我们知道,两个数组表示 ( l , l + 2 k − 1 ) (l, l + 2^{k} - 1) l,l+2k1 ( r − 2 k + 1 , r ) (r - 2^{k} + 1, r) r2k+1,r所以我们只需要证明这两个区间覆盖了 l — — r l —— r lr及证 r − 2 k + 1 < = l + 2 k − 1 r - 2^{k} + 1 <= l + 2^{k} - 1 r2k+1<=l+2k1,这里用移项然后再带入k最后的到 r − l > = 0 r-l>=0 rl>=0,及原式成立。

代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std; 
const int MAXN = 1e6 + 5;

int n, m, x, y, a[MAXN], f[MAXN][105];
void ST(int n) {
	for(int i = 1;i <= n; i++) {
		f[i][0] = a[i];
	}
	int t = log(n) / log(2) + 1;
	for(int j = 1;j < t; j++) {
		for(int i = 1; i <= n - (1 << j) + 1; i++) {
			f[i][j] = max(f[i][j - 1], f[i + (1<<(j-1))][j - 1]);
		}
	} 
} 

int STF(int l, int r) {
	int k = log(r - l + 1) / log(2);
	return max(f[l][k], f[r - (1 << k) + 1][k]);
}
int main() {
	scanf("%d %d", &n, &m);
	for(int i = 1;i <= n; i++) {
		scanf("%d", &a[i]);
	}
	ST(n);
	for(int i = 1;i <= m; i++) {
		scanf("%d %d", &x, &y);
		printf("%d\n", STF(x, y));
	}
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值