RMQ问题(ST表)

ST表是一种用于处理静态RMQ问题(无修改区间最值问题)的最快数据结构,书写方便使用简单效率便捷。其中其预处理复杂度为O(nlogn),查询复杂度为O(1)。总时间复杂度为O(nlogn)。常数远小于树状数组、线段树等毒瘤数据结构。

ST表在预处理时采用倍增以及DP思想,即设f[i][j]为i向右2j个坐标的最大值。在DP时以j为阶段进行转移。
(预处理图):
在这里插入图片描述

在查询时,由于2的(被查询区间长度的对数的两倍)个单位(即2 2*log(len))一定大于区间长度,所以可以查询左右端点向中间2log(len)-1个单位的最大值,取max即为答案。

(查询图):

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define ll long long
#define ull unsigned long long
#define PII pair<int, int>
#define PLI pair<ll, ll>
#define PIL pair<int, ll>
#define endl '\n'
#define IOS std::ios::sync_with_stdio(false),cin.tie(0), cout.tie(0)
#define debug(x) cerr << #x <<" = "<< x << endl
#define debug(x, y) cerr << #x << " = " << x << " and " << #y << " = " << y << endl
#define Pi acos(-1)
using namespace std;

const int N = 1e5 + 100;
int a[N], st[N][30]; //a[]——原数组,st[][]——st表
int n, m;

void init()
{
	for(int i = 1; i <= n; i ++)
		st[i][0] = a[i];  //长度为1的时候
	for(int j = 1; (1 << j) <= n; j ++)
		for(int i = 1; i + (1 << j) - 1 <= n; i ++)
				 //(限制条件)这里需要-1是因为
				//长度为2^j的时候包括了i自己
				st[i][j] = max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
				// 从i开始(包括i)长度为2 ^ (j - 1) 以及
				// 从 i + 2 ^ (j - 1) 开始(包括左端点)
				//长度为 2 ^ (j - 1).
}

int query(int x, int y)
{
	int len = (int)(log((double)(y - x + 1)) / log(2.0)); 
	//注意log函数参数是double型
	return max(st[x][len], st[y - (1 << len) + 1][len]); 
	//是以x为头长度为len 以及
	// 以y为尾长度为len(+1是因为包括y自身)
} 

int main()
{
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
	init();
	while(m --)
	{
		int x, y;
		scanf("%d%d", &x, &y);
		printf("%d\n", query(x, y));
	}
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值