浅谈 ST 算法

假装没事ソ 提交于 2020-03-30 15:27:14

注:本文的确是浅谈,因为觉得不难 -.-

在我们求解 RMQ (区间最大(小)值)的时候,如果没有修改操作(就是离线),那么 ST 算法是很好的选择

空间按复杂度 \(O(n \log n)\) ,时间复杂是预处理的 \(O(n\log n)\) 和 查询的 \(O(1)\),其实用到的思想是 dp 和倍增

倍增的思想就是通过 2 的幂次来增快枚举,其实就是一个小dp。

定义

\(f[i][j]\) 表示 在 \(i\) 下标开始长度为 \(2^j\) 的区间了的最大(小)值

方程

\[f[i][j] = \max or \min(f[i][j - 1],f[i + 2 ^{j - 1}][j - 1]) \]

所求

假设查询区间 \([l,r]\) 的 RMQ 那么有 \(ans = \max or \min (f[l][\log_2 (r - l + 1)], f[r- 2^{\log_2 (r-l + 1)} + 1][\log_2(r - l + 1)])\)

于是一个简单的 dp 就可以完成。确实没什么好说的

#define _CRT_SECURE_NO_WARNINS

#include <bits/stdc++.h>

using namespace std;

template <typename T>
inline T read()
{
	T x = 0;
	char ch = getchar();
	bool f = 0;
	while(ch < '0' || ch > '9')
	{
		f = (ch == '-');
		ch = getchar();
	}
	while(ch <= '9' && ch >= '0')
	{
		x = (x << 1) + (x << 3) + (ch - '0');
		ch = getchar();
	}
	return  f? -x : x;
}

template <typename T>
void put(T x)
{
	if(x < 0)
	{
		x = -x;
		putchar('-');
		}
	if(x < 10) {
		putchar(x + 48);
		return;
	}
	put(x / 10);
	putchar(x % 10 + 48);
	return ;
}

const int Maxn = 1e5 + 11;

int n, q, f[Maxn][18], l, r, bin[22];

inline int query(int r, int l) { int k = log2(r - l + 1); return max(f[l][k], f[r - (1 << k) + 1][k]); }

int main()
{
	n = read <int> ();
	q = read <int> ();
	for(int i = 1; i <= n; ++i) f[i][0] = read <int> ();
	int tmp1 = log2(n);
	for(int i = 1; i <= tmp1; ++i)
	{
		int tmp = 1 << i;
		for(int j = 1; j <= n - tmp + 1; ++j) f[j][i] = max(f[j][i - 1], f[j + tmp / 2][i - 1]);
	}
	while(q--)
	{
		put(query(read <int> (), read <int> ()));
		putchar('\n');
	}
	return 0;
}

据说有一种求 RMQ 的方法可以做到 \(O(n)\) 预处理,\(O(1)\) 查询,而且支持在线,好像叫约束 RMQ......QAQ

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!