---ST---

例题

ST 算法类似分块,但分块的大小不一样,ST 表中,第 i 个块大小为 2 i 2^i 2i ,我们用 f [ i ] [ j ] f[i][j] f[i][j] 表示区间 [ i , i + 2 j − 1 ] [i,i+2^j-1] [i,i+2j1] 的最值,易得 长度为 c c c 的区间 [ l , r ] [l,r] [l,r] 的最值等于 max ⁡ ( f [ l ] [ log ⁡ 2 c ] , f [ r − 2 l o g 2 c ] [ l o g 2 c ] ) \max(f[l][\log_2c],f[r-2^{log_2c}][log_2c]) max(f[l][log2c],f[r2log2c][log2c]) (两个区间有重叠的部分,但是不影响) 这里的 log 都是下取整的, f [ i ] [ j ] = max ⁡ ( f [ i ] [ j − 1 ] , f [ i + 2 j − 1 ] [ j − 1 ] ) f[i][j]=\max(f[i][j-1],f[i+2^{j-1}][j-1]) f[i][j]=max(f[i][j1],f[i+2j1][j1]) 于是我们可以用 O ( n log ⁡ n ) O(n\log n) O(nlogn) 的时间算出 f [ ] [ ] f[][] f[][] ,然后 O ( 1 ) O(1) O(1) 查询,因为 cmath 的 log 效率不高,所以我们也可以预处理, ⌊ log ⁡ 2 x ⌋ = ⌊ log ⁡ 2 ⌊ x 2 ⌋ ⌋ + 1 \lfloor \log_2x \rfloor = \lfloor \log_2{\lfloor \frac{x}{2} \rfloor}\rfloor +1 log2x=log22x+1

代码:

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define rp(i, e) for(int i=1;i<=(e);i++)
#define pr(i, e) for(int i=(e);i>=1;i--)
#define rp0(i, e) for(int i=0;i<(e);i++)
#define pr0(i, e) for(int i=(e-1);i>=0;i--)
#define rps(i, b, e) for(int i=(b);i<=(e);i++)
#define prs(i, e, b) for(int i=(e);i>=(b);i--)
#define rpg(i, x) for(int i=head[x];i;i=e[i].nxt)
#define opf(s) freopen(s".in", "r", stdin), freopen(s".out", "w", stdout)
using namespace std;
const int NR=1e5+10, CFR=20;
int n, a[NR], f[NR][CFR+5], lg[NR];
//f[i][j]表示a[i~(i+2^j-1)]的最大值
//f[i][j]=max(f[i][j-1], f[i+2^(j-1)][j-1])
//max{[l,r]}=max(f[l][log(r-l)], f[r-2^(log(r-l))+1][log(r-l)]) 
int main()
{
	int T, l, r;
	scanf("%d%d", &n, &T);
	rp(i, n)scanf("%d", a+i);
	rps(i, 2, n)lg[i]=lg[i>>1]+1;
	rp(i, n)f[i][0]=a[i];
	rp(j, lg[n])
		rps(i, 1, n-(1<<j)+1)
			f[i][j]=max(f[i][j-1], f[i+(1<<j-1)][j-1]);
	while(T--)
	{
		scanf("%d%d", &l, &r);
		printf("%d\n", max(f[l][lg[r-l+!]], f[r-(1<<lg[r-l+1])+1][lg[r-l+1]]));
	}
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值