Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
range_minimum_query.h
Go to the documentation of this file.
1// Copyright 2010-2024 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14// We use the notation min(arr, i, j) for the minimum arr[x] such that i <= x
15// and x < j.
16// Range Minimum Query (RMQ) is a data structure preprocessing an array arr so
17// that querying min(arr, i, j) takes O(1) time. The preprocessing takes
18// O(n*log(n)) time and memory.
19
20// Note: There exists an O(n) preprocessing algorithm, but it is considerably
21// more involved and the hidden constants behind it are much higher.
22//
23// The algorithms are well explained in Wikipedia:
24// https://en.wikipedia.org/wiki/Range_minimum_query.
25//
26//
27// Implementation: The idea is to cache every min(arr, i, j) where j - i is a
28// power of two, i.e. j = i + 2^k for some k. Provided this information, we can
29// answer all queries in O(1): given a pair (i, j) find the maximum k such that
30// i + 2^k < j and note that
31// std::min(min(arr, i, i+2^k), min(arr, j-2^k, j)) = min(arr, i, j).
32
33#ifndef OR_TOOLS_UTIL_RANGE_MINIMUM_QUERY_H_
34#define OR_TOOLS_UTIL_RANGE_MINIMUM_QUERY_H_
35
36#include <algorithm>
37#include <functional>
38#include <numeric>
39#include <utility>
40#include <vector>
41
42#include "ortools/util/bitset.h"
43
44namespace operations_research {
45template <typename T, typename Compare = std::less<T>>
47 public:
48 explicit RangeMinimumQuery(std::vector<T> array);
49 RangeMinimumQuery(std::vector<T> array, Compare cmp);
50
51 // This type is neither copyable nor movable.
54
55 // Returns the minimum (w.r.t. Compare) arr[x], where x is contained in
56 // [from, to).
57 T GetMinimumFromRange(int from, int to) const;
58
59 const std::vector<T>& array() const;
60
61 private:
62 // cache_[k][i] = min(arr, i, i+2^k).
63 std::vector<std::vector<T>> cache_;
64 Compare cmp_;
65};
66
67// RangeMinimumIndexQuery is similar to RangeMinimumQuery, but
68// GetMinimumIndexFromRange returns the index for which the minimum is attained.
69template <typename T, typename Compare = std::less<T>>
71 public:
72 explicit RangeMinimumIndexQuery(std::vector<T> array);
73 RangeMinimumIndexQuery(std::vector<T> array, Compare cmp);
74
75 // This type is neither copyable nor movable.
78
79 // Returns an index idx from [from, to) such that arr[idx] is the minimum
80 // value of arr over the interval [from, to).
81 int GetMinimumIndexFromRange(int from, int to) const;
82
83 // Returns the original array.
84 const std::vector<T>& array() const;
85
86 private:
87 // Returns a vector with values 0, 1, ... n - 1 for a given n.
88 static std::vector<int> CreateIndexVector(int n);
89 struct IndexComparator {
90 bool operator()(int lhs_idx, int rhs_idx) const;
91 const std::vector<T> array;
92 Compare cmp;
93 } cmp_;
95};
96
97// RangeMinimumQuery implementation
98template <typename T, typename Compare>
100 : RangeMinimumQuery(std::move(array), Compare()) {}
101
102// Reminder: The task is to fill cache_ so that
103// cache_[k][i] = min(arr, i, i+2^k) for every k <= Log2(n) and i <= n-2^k.
104// Note that cache_[k+1][i] = min(cache_[k][i], cache_[k][i+2^k]), hence every
105// row can be efficiently computed from the previous.
106template <typename T, typename Compare>
108 Compare cmp)
109 : cache_(MostSignificantBitPosition32(array.size()) + 1),
110 cmp_(std::move(cmp)) {
111 const int array_size = array.size();
112 cache_[0] = std::move(array);
113 for (int row_idx = 1; row_idx < cache_.size(); ++row_idx) {
114 const int row_length = array_size - (1 << row_idx) + 1;
115 const int window = 1 << (row_idx - 1);
116 cache_[row_idx].resize(row_length);
117 for (int col_idx = 0; col_idx < row_length; ++col_idx) {
118 cache_[row_idx][col_idx] =
119 std::min(cache_[row_idx - 1][col_idx],
120 cache_[row_idx - 1][col_idx + window], cmp_);
121 }
122 }
123}
124
125template <typename T, typename Compare>
127 int to) const {
128 DCHECK_LE(0, from);
129 DCHECK_LT(from, to);
130 DCHECK_LE(to, array().size());
131 const int log_diff = MostSignificantBitPosition32(to - from);
132 const int window = 1 << log_diff;
133 const std::vector<T>& row = cache_[log_diff];
134 return std::min(row[from], row[to - window], cmp_);
135}
136
137template <typename T, typename Compare>
138inline const std::vector<T>& RangeMinimumQuery<T, Compare>::array() const {
139 return cache_[0];
140}
141
142// RangeMinimumIndexQuery implementation
143template <typename T, typename Compare>
145 std::vector<T> array)
146 : RangeMinimumIndexQuery(std::move(array), Compare()) {}
147
148template <typename T, typename Compare>
150 Compare cmp)
151 : cmp_({std::move(array), std::move(cmp)}),
152 rmq_(CreateIndexVector(cmp_.array.size()), cmp_) {}
153
154template <typename T, typename Compare>
156 int from, int to) const {
157 return rmq_.GetMinimumFromRange(from, to);
158}
159
160template <typename T, typename Compare>
162 int lhs_idx, int rhs_idx) const {
163 return cmp(array[lhs_idx], array[rhs_idx]);
164}
165
166template <typename T, typename Compare>
167std::vector<int> RangeMinimumIndexQuery<T, Compare>::CreateIndexVector(int n) {
168 std::vector<int> result(n, 0);
169 std::iota(result.begin(), result.end(), 0);
170 return result;
171}
172
173template <typename T, typename Compare>
174inline const std::vector<T>& RangeMinimumIndexQuery<T, Compare>::array() const {
175 return cmp_.array;
176}
177} // namespace operations_research
178#endif // OR_TOOLS_UTIL_RANGE_MINIMUM_QUERY_H_
IntegerValue size
RangeMinimumIndexQuery(const RangeMinimumIndexQuery &)=delete
This type is neither copyable nor movable.
RangeMinimumIndexQuery(std::vector< T > array)
RangeMinimumIndexQuery implementation.
const std::vector< T > & array() const
Returns the original array.
RangeMinimumIndexQuery & operator=(const RangeMinimumIndexQuery &)=delete
int GetMinimumIndexFromRange(int from, int to) const
T GetMinimumFromRange(int from, int to) const
const std::vector< T > & array() const
RangeMinimumQuery(std::vector< T > array, Compare cmp)
RangeMinimumQuery & operator=(const RangeMinimumQuery &)=delete
RangeMinimumQuery(const RangeMinimumQuery &)=delete
This type is neither copyable nor movable.
RangeMinimumQuery(std::vector< T > array)
RangeMinimumQuery implementation.
RowIndex row
Definition markowitz.cc:186
In SWIG mode, we don't want anything besides these top-level includes.
int MostSignificantBitPosition32(uint32_t n)
Definition bitset.h:277
STL namespace.
trees with all degrees equal to