Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitd2a3810

Browse files
authored
Small fixes.
1 parentba84614 commitd2a3810

File tree

1 file changed

+28
-101
lines changed

1 file changed

+28
-101
lines changed

‎src/num_methods/binary_search.md

Lines changed: 28 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ while (r - l > 1) {
7171

7272
During the execution of the algorithm, we never evaluate neither $A_L$ nor $A_R$, as $L < M < R$. In the end, $L$ will be the index of the last element that is not greater than $k$ (or $-1$ if there is no such element) and $R$ will be the index of the first element larger than $k$ (or $n$ if there is no such element).
7373

74-
**Note.** Calculating`m` as`m = (r + l) / 2` can lead to overflow if`l` and`r` are two positive integers, and this error lived about 9 years in JDK as described in the[blogpost](https://ai.googleblog.com/2006/06/extra-extra-read-all-about-it-nearly.html). Some alternative approaches include e.g. writing`m = l + (r - l) / 2` which always works for positive integer`l` and`r`, but might still overflow if`l` is a negative number. If you use C++20, it offers an alternative solution in the form of`m = midpoint(l, r)` which always works correctly.
74+
**Note.** Calculating`m` as`m = (r + l) / 2` can lead to overflow if`l` and`r` are two positive integers, and this error lived about 9 years in JDK as described in the[blogpost](https://ai.googleblog.com/2006/06/extra-extra-read-all-about-it-nearly.html). Some alternative approaches include e.g. writing`m = l + (r - l) / 2` which always works for positive integer`l` and`r`, but might still overflow if`l` is a negative number. If you use C++20, it offers an alternative solution in the form of`m =std::midpoint(l, r)` which always works correctly.
7575

7676
##Search on arbitrary predicate
7777

@@ -138,126 +138,56 @@ Another noteworthy way to do binary search is, instead of maintaining an active
138138

139139
This paradigm is widely used in tasks around trees, such as finding lowest common ancestor of two vertices or finding an ancestor of a specific vertex that has a certain height. It could also be adapted to e.g. find the $k$-th non-zero element in a Fenwick tree.
140140

141-
##Parallel Binary Search
141+
##Parallel Binary Search
142142

143-
[^1] Imaginethatwe want to answer $Z$ queries abouttheindex of the largest value less than or equal to some $X_i$ (for $i=1,2,\ldots,Z$) in some sorted 0-indexed array $A$. Naturally, each query can be answered using binary search.
143+
<small>Notethatthis section is followingthedescription in[Sports programming in practice](https://kostka.dev/sp/).</small>
144144

145-
Specifally, let us consider the following array $A$:
146-
147-
| $A_0$| $A_1$| $A_2$| $A_3$| $A_4$| $A_5$| $A_6$| $A_7$|
148-
|-------|-------|-------|-------|-------|-------|-------|-------|
149-
| 1| 3| 5| 7| 9| 9| 13| 15|
145+
Imagine that we want to answer $Z$ queries about the index of the largest value less than or equal to some $X_i$ (for $i=1,2,\ldots,Z$) in some sorted 0-indexed array $A$. Naturally, each query can be answered using binary search.
150146

147+
Specifally, let us consider the following array $A =[1,3,5,7,9,9,13,15]$
151148
with queries: $X =[8,11,4,5]$. We can use binary search for each query sequentially.
152149

153-
<table>
154-
<tr>
155-
<th>query</th>
156-
<th>$ X_1 = 8 $</th>
157-
<th>$ X_2 = 11 $</th>
158-
<th>$ X_3 = 4 $</th>
159-
<th>$ X_4 = 5 $</th>
160-
</tr>
161-
<tr>
162-
<th rowspan="3">step 1</th>
163-
<td>answer in $[0,7]$</td>
164-
<td>answer in $[0,7]$</td>
165-
<td>answer in $[0,7]$</td>
166-
<td>answer in $[0,7]$</td>
167-
</tr>
168-
<tr>
169-
<td>check $ A_4 $</td>
170-
<td>check $ A_4 $</td>
171-
<td>check $ A_4 $</td>
172-
<td>check $ A_4 $</td>
173-
</tr>
174-
<tr>
175-
<td>$ X_1 < A_4 = 9 $</td>
176-
<td>$ X_2 \geq A_4 = 9 $</td>
177-
<td>$ X_3 < A_4 = 9 $</td>
178-
<td>$ X_4 < A_4 = 9 $</td>
179-
</tr>
180-
<tr>
181-
<th rowspan="3">step 2</th>
182-
<td>answer in $[0,3]$</td>
183-
<td>answer in $[4,7]$</td>
184-
<td>answer in $[0,3]$</td>
185-
<td>answer in $[0,3]$</td>
186-
</tr>
187-
<tr>
188-
<td>check $ A_2 $</td>
189-
<td>check $ A_6 $</td>
190-
<td>check $ A_2 $</td>
191-
<td>check $ A_2 $</td>
192-
</tr>
193-
<tr>
194-
<td>$ X_1 \geq A_2 = 5 $</td>
195-
<td>$ X_2 < A_6 = 13 $</td>
196-
<td>$ X_3 < A_2 = 5 $</td>
197-
<td>$ X_4 \geq A_2 = 5 $</td>
198-
</tr>
199-
<tr>
200-
<th rowspan="3">step 3</th>
201-
<td>answer in $[2,3]$</td>
202-
<td>answer in $[4,5]$</td>
203-
<td>answer in $[0,1]$</td>
204-
<td>answer in $[2,3]$</td>
205-
</tr>
206-
<tr>
207-
<td>check $ A_3 $</td>
208-
<td>check $ A_5 $</td>
209-
<td>check $ A_1 $</td>
210-
<td>check $ A_3 $</td>
211-
</tr>
212-
<tr>
213-
<td>$ X_1 \geq A_3 = 7 $</td>
214-
<td>$ X_2 \geq A_5 = 9 $</td>
215-
<td>$ X_3 \geq A_1 = 3 $</td>
216-
<td>$ X_4 < A_3 = 7 $</td>
217-
</tr>
218-
<tr>
219-
<th rowspan="2">step 4</th>
220-
<td>answer in $[3,3]$</td>
221-
<td>answer in $[5,5]$</td>
222-
<td>answer in $[1,1]$</td>
223-
<td>answer in $[2,2]$</td>
224-
</tr>
225-
<tr>
226-
<td>$ index = 3 $</td>
227-
<td>$ index = 5 $</td>
228-
<td>$ index = 1 $</td>
229-
<td>$ index = 2 $</td>
230-
</tr>
231-
</table>
232-
150+
| query|\( X_1 = 8\)|\( X_2 = 11\)|\( X_3 = 4\)|\( X_4 = 5\)|
151+
|--------|------------------------|------------------------|-----------------------|-----------------------|
152+
|**step 1**| answer in\([0,8)\)| answer in\([0,8)\)| answer in\([0,8)\)| answer in\([0,8)\)|
153+
|| check\( A_4\)| check\( A_4\)| check\( A_4\)| check\( A_4\)|
154+
||\( X_1 < A_4 = 9\)|\( X_2 \geq A_4 = 9\)|\( X_3 < A_4 = 9\)|\( X_4 < A_4 = 9\)|
155+
|**step 2**| answer in\([0,4)\)| answer in\([4,8)\)| answer in\([0,4)\)| answer in\([0,4)\)|
156+
|| check\( A_2\)| check\( A_6\)| check\( A_2\)| check\( A_2\)|
157+
||\( X_1 \geq A_2 = 5\)|\( X_2 < A_6 = 13\)|\( X_3 < A_2 = 5\)|\( X_4 \geq A_2 = 5\)|
158+
|**step 3**| answer in\([2,4)\)| answer in\([4,6)\)| answer in\([0,2)\)| answer in\([2,4)\)|
159+
|| check\( A_3\)| check\( A_5\)| check\( A_1\)| check\( A_3\)|
160+
||\( X_1 \geq A_3 = 7\)|\( X_2 \geq A_5 = 9\)|\( X_3 \geq A_1 = 3\)|\( X_4 < A_3 = 7\)|
161+
|**step 4**| answer in\([3,4)\)| answer in\([5,6)\)| answer in\([1,2)\)| answer in\([2,3)\)|
162+
||\( index = 3\)|\( index = 5\)|\( index = 1\)|\( index = 2\)|
233163

234164
We generally process this table by columns (queries), but notice that in each row we often repeat access to certain values of our array. To limit access to the values, we can process the table by rows (steps). This does not make huge difference in our small example problem (as we can access all elements in $\mathcal{O}(1)$), but in more complex problems, where computing these values is more complicated, this might be essential to solve these problems efficiently. Moreover, note that we can arbitrarily choose the order in which we answer questions in a single row. Let us look at the code implementing this approach.
235165

236-
```cpp
166+
```{.cpp file=parallel-binary-search}
237167
// Computes the index of the largest value in table A less than or equal to $X_i$ for all $i$.
238168
vector<int>ParallelBinarySearch(vector<int>& A, vector<int>& X) {
239169
int N = A.size();
240170
int M = X.size();
241-
vector<int>P(M, -1);
242-
vector<int>Q(M, N-1);
171+
vector<int>left(M, -1);
172+
vector<int>right(M, N-1);
243173

244174
for (int step = 1; step <= ceil(log2(N)); ++step) {
245175
// Map to store indices of queries asking for this value.
246-
unordered_map<int, vector<int>>important_values;
176+
unordered_map<int, vector<int>>mid_to_queries;
247177

248178
// Calculate mid and populate the important_values map.
249179
for (int i = 0; i < M; ++i) {
250-
int mid = (P[i] +Q[i]) / 2;
251-
important_values[mid].push_back(i);
180+
int mid = (left[i] +right[i]) / 2;
181+
mid_to_queries[mid].push_back(i);
252182
}
253183

254184
// Process each value in important_values.
255-
for (const auto& [mid, queries]:important_values) {
185+
for (const auto& [mid, queries]:mid_to_queries) {
256186
for (int query : queries) {
257187
if (A[mid] > X[query]) {
258-
Q[query] = mid;
188+
right[query] = mid;
259189
} else {
260-
P[query] = mid;
190+
left[query] = mid;
261191
}
262192
}
263193
}
@@ -286,7 +216,4 @@ vector<int> ParallelBinarySearch(vector<int>& A, vector<int>& X) {
286216
### Parallel Binary Search
287217
288218
* [Szkopul - Meteors](https://szkopul.edu.pl/problemset/problem/7JrCYZ7LhEK4nBR5zbAXpcmM/site/?key=statement)
289-
* [AtCoder - Stamp Rally](https://atcoder.jp/contests/agc002/tasks/agc002_d)
290-
291-
292-
[^1]: Note that this section is following the description in [Sports programming in practice](https://kostka.dev/sp/).
219+
* [AtCoder - Stamp Rally](https://atcoder.jp/contests/agc002/tasks/agc002_d)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp