Four Russian RMQ算法的C++实现

Four Russian RMQ算法的基本思想是对原序列分块,对每块及块间均建立ST表,从而处理块内和块间查询,具体见以下代码
C++代码:

#include <iostream>
#include <vector>
#include <random>
using namespace std;

size_t log2(size_t N)
{
	size_t k = 0;
	while (1ull << k <= N)
	{
		++k;
	}
	--k;
	return k;
}

template <typename T>
struct m_info
{
	T m_value;
	size_t index;
	m_info(const T &m, size_t i) :m_value(m), index(i) {}
	m_info() = default;
	bool operator == (const m_info& be_compared)const { return m_value == be_compared.m_value && index == be_compared.index; }
};

template <typename T>
const m_info<T>& min_m_info(const m_info<T>& left, const m_info<T>& right)
{
	if (left.m_value <= right.m_value)
	{
		return left;
	}
	return right;
}

template <typename T>
void SparseTable(vector<vector<m_info<T>>>& d, vector<T>& seq, size_t left, size_t right)  //[left, right]从0开始
{
	for (size_t i = 0; i <= right - left; ++i)
	{
		d[i][0] = m_info<T>(seq[i + left], i);
	}

	for (size_t i = 1; (1 << i) <= right - left + 1; ++i)
	{
		for (size_t j = 0; j <= right - left + 1 - (1 << i); ++j)
		{
			if (d[j][i - 1].m_value <= d[j + (1 << i - 1)][i - 1].m_value)
			{
				d[j][i] = d[j][i - 1];
			}
			else
			{
				d[j][i] = d[j + (1 << i - 1)][i - 1];
			}
		}
	}
}

template <typename T>
m_info<T> query(size_t i, size_t j, vector<vector<m_info<T>>>& d)  //i,j从0开始算
{
	size_t l = j - i + 1;
	size_t k = log2(l);
	if (d[i][k].m_value <= d[j - (1 << k) + 1][k].m_value)
		return d[i][k];
	return d[j - (1 << k) + 1][k];
}

template <typename T>
class FourRussianRMQ
{
public:
	m_info<T> queryRMQ(size_t i, size_t j);
	FourRussianRMQ(vector<T>& v, size_t s, const T& m);
private:
	T max_value_for_type;
	size_t N;
	size_t segment_length;
	size_t block_num;
	vector<T> value_seq;
	vector<vector<vector<m_info<T>>>> group_in_query_map_table;
	vector<vector<m_info<T>>> group_between_query_table;
	vector<vector<m_info<T>>> prefix_RMQ;
	vector<vector<m_info<T>>> suffix_RMQ;
	void preProcess();
};

template <typename T>
m_info<T> FourRussianRMQ<T>::queryRMQ(size_t i, size_t j)
{
	if (i > j || j >= N)
	{
		cout << "非法的查询索引!" << endl;
		exit(-1);
	}

	size_t i_block_index = i / segment_length;
	size_t i_in_block_index = i % segment_length;
	size_t j_block_index = j / segment_length;
	size_t j_in_block_index = j % segment_length;
	m_info<T> result;
	size_t first_value_in_block_offset;
	if (i_block_index == j_block_index)
	{
		if (i_in_block_index == 0)
		{
			result = prefix_RMQ[i_block_index][j_in_block_index];
		}
		else if (j_in_block_index == segment_length - 1)
		{
			result = suffix_RMQ[i_block_index][i_in_block_index];
		}
		else
		{
			result = query(i_in_block_index, j_in_block_index, group_in_query_map_table[i_block_index]);
		}
		
		first_value_in_block_offset = i_block_index * segment_length;
	}
	else
	{
		if (i_in_block_index == 0 && j_in_block_index == segment_length - 1)
		{
			result = query(i_block_index, j_block_index, group_between_query_table);
			size_t block_index = result.index;
			result = prefix_RMQ[block_index][segment_length - 1];
			first_value_in_block_offset = block_index * segment_length;
		}
		else
		{
			m_info<T> r_ref;
			m_info<T> result2;
			m_info<T> result3;
			size_t block_index;
			if (i_block_index + 1 == j_block_index)
			{
				result2 = suffix_RMQ[i_block_index][i_in_block_index];
				result3 = prefix_RMQ[j_block_index][j_in_block_index];
				r_ref = min_m_info(result2, result3);
			}
			else
			{
				if (i_in_block_index == 0)
				{
					result = query(i_block_index, j_block_index - 1, group_between_query_table);
				}
				else if (j_in_block_index == segment_length - 1)
				{
					result = query(i_block_index + 1, j_block_index, group_between_query_table);
				}
				else  
				{
					result = query(i_block_index + 1, j_block_index - 1, group_between_query_table);
				}

				block_index = result.index;
				result = prefix_RMQ[block_index][segment_length - 1];

				if (i_in_block_index == 0 || j_in_block_index == segment_length - 1)
				{
					if (i_in_block_index == 0)
					{
						result2 = prefix_RMQ[j_block_index][j_in_block_index];
					}
					else
					{
						result2 = suffix_RMQ[i_block_index][i_in_block_index];
					}
					r_ref = min_m_info(result, result2);
				}
				else
				{
					result2 = suffix_RMQ[i_block_index][i_in_block_index];
					result3 = prefix_RMQ[j_block_index][j_in_block_index];
					r_ref = min_m_info(result, min_m_info(result2, result3));
				}
			}

			if (i_block_index + 1 != j_block_index && r_ref == result)
			{
				first_value_in_block_offset = block_index * segment_length;
			}
			else
			{
				if (i_block_index + 1 == j_block_index && r_ref == result3 || i_block_index + 1 != j_block_index && (i_in_block_index != 0 && j_in_block_index != segment_length - 1 && r_ref == result3))
				{
					first_value_in_block_offset = j_block_index * segment_length;
					result3.index += first_value_in_block_offset;
					return result3;
				}
				else
				{
					if (i_block_index + 1 != j_block_index && i_in_block_index == 0)
					{
						first_value_in_block_offset = j_block_index * segment_length;
					}
					else
					{
						first_value_in_block_offset = i_block_index * segment_length;
					}

					result2.index += first_value_in_block_offset;
					return result2;
				}
			}
		}
	}
	result.index += first_value_in_block_offset;
	return result;
}

template <typename T>
void FourRussianRMQ<T>::preProcess()
{
	vector<T> m_value_for_every_block(block_num);
	size_t start_index_for_left_bound = 0;
	for (size_t i = 0; i < block_num; ++i)
	{   
		prefix_RMQ[i][0] = m_info<T>(value_seq[start_index_for_left_bound], 0);
		for (size_t j = start_index_for_left_bound + 1; j < start_index_for_left_bound + segment_length; ++j)
		{
			if (value_seq[j] < prefix_RMQ[i][j - start_index_for_left_bound - 1].m_value)
			{
				prefix_RMQ[i][j - start_index_for_left_bound] = m_info<T>(value_seq[j], j - start_index_for_left_bound);
			}
			else
			{
				prefix_RMQ[i][j - start_index_for_left_bound] = prefix_RMQ[i][j - start_index_for_left_bound - 1];
			}
		}

		suffix_RMQ[i][segment_length - 1] = m_info<T>(value_seq[start_index_for_left_bound + segment_length - 1], segment_length - 1);
		if (segment_length > 1)
		{
			for (size_t j = start_index_for_left_bound + segment_length - 2; ; --j)
			{
				if (value_seq[j] < suffix_RMQ[i][j - start_index_for_left_bound + 1].m_value)
				{
					suffix_RMQ[i][j - start_index_for_left_bound] = m_info<T>(value_seq[j], j - start_index_for_left_bound);
				}
				else
				{
					suffix_RMQ[i][j - start_index_for_left_bound] = suffix_RMQ[i][j - start_index_for_left_bound + 1];
				}
				if (j == start_index_for_left_bound)
				{
					break;
				}
			}
		}

		SparseTable(group_in_query_map_table[i], value_seq, start_index_for_left_bound, start_index_for_left_bound + segment_length - 1);
		start_index_for_left_bound = start_index_for_left_bound + segment_length;
		m_value_for_every_block[i] = query(0, segment_length - 1, group_in_query_map_table[i]).m_value;
	}
	SparseTable(group_between_query_table, m_value_for_every_block, 0, m_value_for_every_block.size() - 1);
}

template <typename T>
FourRussianRMQ<T>::FourRussianRMQ(vector<T>& v, size_t s, const T &m):value_seq(v), N(v.size()), segment_length(s) ,block_num(N % segment_length != 0 ? N / segment_length + 1 : N / segment_length), group_in_query_map_table(block_num, vector<vector<m_info<T>>>(segment_length, vector<m_info<T>>(log2(segment_length) + 1))),
group_between_query_table(block_num, vector<m_info<T>>(log2(block_num) + 1)), prefix_RMQ(block_num, vector<m_info<T>>(segment_length)),
suffix_RMQ(block_num, vector<m_info<T>>(segment_length)), max_value_for_type(m)
{
	if (value_seq.empty())
	{
		cout << "ERROR输入序列为空!" << endl;
		exit(-1);
	}

	if (segment_length > N)
	{
		cout << "ERROR分块长度应小于等于输入序列长度" << endl;
		exit(-1);
	}

	size_t r;
	if ((r = N % segment_length) != 0)
	{
		r = segment_length - r;
		for (size_t i = 1; i <= r; ++i)
		{
			value_seq.push_back(m);
		}
	}
	preProcess();
}

int main()
{
	const int N = 256;
	vector<long long> rmq_seq(N);
	for (size_t i = 0; i < N; ++i)
	{
		rmq_seq[i] = i + 1;
	}
	shuffle(rmq_seq.begin(), rmq_seq.end(), default_random_engine());
	FourRussianRMQ<long long> obj(rmq_seq, 2, 0xffffffffffffffffull >> 1);
	for (size_t i = 0; i < rmq_seq.size() - 1; ++i)
	{
		for (size_t j = i + 1; j < rmq_seq.size(); ++j)
		{
			m_info<long long> r = obj.queryRMQ(i, j);
			long long m = rmq_seq[i];
			for (size_t k = i + 1; k <= j; ++k)
			{
				if (rmq_seq[k] < m)
				{
					m = rmq_seq[k];
				}
			}
			if (r.m_value == m && rmq_seq[r.index] == m)
			{
				cout << "[" << i << "," << j << "]查询结果正确!" << endl;
			}
			else
			{
				cout << "[" << i << "," << j << "]查询结果错误!" << endl;
				exit(-1);
			}
		}
	}
    return 0;
}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
抱歉,我不确定您指的是哪种RMQ算法。一般来说,RMQ是“区间最小值查询”(Range Minimum Query)的缩写,其实现算法有多种。以下是两种常见的RMQ算法实现代码,供参考: 1. 线段树RMQ算法 ```python class SegmentTree: def __init__(self, arr): self.tree = [0] * (4 * len(arr)) self.build(arr, 0, 0, len(arr) - 1) def build(self, arr, index, left, right): if left == right: self.tree[index] = arr[left] else: mid = (left + right) // 2 self.build(arr, index * 2 + 1, left, mid) self.build(arr, index * 2 + 2, mid + 1, right) self.tree[index] = min(self.tree[index * 2 + 1], self.tree[index * 2 + 2]) def query(self, index, left, right, qleft, qright): if left > qright or right < qleft: return float('inf') elif qleft <= left and qright >= right: return self.tree[index] else: mid = (left + right) // 2 return min(self.query(index * 2 + 1, left, mid, qleft, qright), self.query(index * 2 + 2, mid + 1, right, qleft, qright)) # 示例 arr = [1, 3, 2, 7, 9, 11] tree = SegmentTree(arr) print(tree.query(0, 0, len(arr) - 1, 1, 4)) # 输出2,即arr[2:5]的最小值 ``` 2. ST算法 ```python import math class ST: def __init__(self, arr): n = len(arr) k = int(math.log2(n)) self.table = [[0] * (k + 1) for _ in range(n)] for i in range(n): self.table[i][0] = arr[i] for j in range(1, k + 1): for i in range(n - 2 ** j + 1): self.table[i][j] = min(self.table[i][j - 1], self.table[i + 2 ** (j - 1)][j - 1]) def query(self, left, right): k = int(math.log2(right - left + 1)) return min(self.table[left][k], self.table[right - 2 ** k + 1][k]) # 示例 arr = [1, 3, 2, 7, 9, 11] st = ST(arr) print(st.query(1, 4)) # 输出2,即arr[2:5]的最小值 ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值