From ba846144e84aa52987549baeede2ef7e0e9d90cc Mon Sep 17 00:00:00 2001 From: Bartosz Kostka Date: Sat, 26 Oct 2024 22:54:57 -0400 Subject: [PATCH 01/10] On Parallel Binary Search --- src/num_methods/binary_search.md | 138 ++++++++++++++++++++++++++++++- 1 file changed, 137 insertions(+), 1 deletion(-) diff --git a/src/num_methods/binary_search.md b/src/num_methods/binary_search.md index b7cc69c56..0fab8c947 100644 --- a/src/num_methods/binary_search.md +++ b/src/num_methods/binary_search.md @@ -71,7 +71,7 @@ while (r - l > 1) { 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). -**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. +**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. ## Search on arbitrary predicate @@ -138,6 +138,134 @@ Another noteworthy way to do binary search is, instead of maintaining an active 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. +## Parallel Binary Search + +[^1] 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. + +Specifally, let us consider the following array $A$: + +| $A_0$ | $A_1$ | $A_2$ | $A_3$ | $A_4$ | $A_5$ | $A_6$ | $A_7$ | +|-------|-------|-------|-------|-------|-------|-------|-------| +| 1 | 3 | 5 | 7 | 9 | 9 | 13 | 15 | + +with queries: $X = [8,11,4,5]$. We can use binary search for each query sequentially. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
query$ X_1 = 8 $$ X_2 = 11 $$ X_3 = 4 $$ X_4 = 5 $
step 1answer in $[0,7]$answer in $[0,7]$answer in $[0,7]$answer in $[0,7]$
check $ A_4 $check $ A_4 $check $ A_4 $check $ A_4 $
$ X_1 < A_4 = 9 $$ X_2 \geq A_4 = 9 $$ X_3 < A_4 = 9 $$ X_4 < A_4 = 9 $
step 2answer in $[0,3]$answer in $[4,7]$answer in $[0,3]$answer in $[0,3]$
check $ A_2 $check $ A_6 $check $ A_2 $check $ A_2 $
$ X_1 \geq A_2 = 5 $$ X_2 < A_6 = 13 $$ X_3 < A_2 = 5 $$ X_4 \geq A_2 = 5 $
step 3answer in $[2,3]$answer in $[4,5]$answer in $[0,1]$answer in $[2,3]$
check $ A_3 $check $ A_5 $check $ A_1 $check $ A_3 $
$ X_1 \geq A_3 = 7 $$ X_2 \geq A_5 = 9 $$ X_3 \geq A_1 = 3 $$ X_4 < A_3 = 7 $
step 4answer in $[3,3]$answer in $[5,5]$answer in $[1,1]$answer in $[2,2]$
$ index = 3 $$ index = 5 $$ index = 1 $$ index = 2 $
+ + +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. + +```cpp +// Computes the index of the largest value in table A less than or equal to $X_i$ for all $i$. +vector ParallelBinarySearch(vector& A, vector& X) { + int N = A.size(); + int M = X.size(); + vector P(M, -1); + vector Q(M, N-1); + + for (int step = 1; step <= ceil(log2(N)); ++step) { + // Map to store indices of queries asking for this value. + unordered_map> important_values; + + // Calculate mid and populate the important_values map. + for (int i = 0; i < M; ++i) { + int mid = (P[i] + Q[i]) / 2; + important_values[mid].push_back(i); + } + + // Process each value in important_values. + for (const auto& [mid, queries]: important_values) { + for (int query : queries) { + if (A[mid] > X[query]) { + Q[query] = mid; + } else { + P[query] = mid; + } + } + } + } + return P; +} +``` + ## Practice Problems * [LeetCode - Find First and Last Position of Element in Sorted Array](https://leetcode.com/problems/find-first-and-last-position-of-element-in-sorted-array/) @@ -154,3 +282,11 @@ This paradigm is widely used in tasks around trees, such as finding lowest commo * [Codeforces - GukiZ hates Boxes](https://codeforces.com/problemset/problem/551/C) * [Codeforces - Enduring Exodus](https://codeforces.com/problemset/problem/645/C) * [Codeforces - Chip 'n Dale Rescue Rangers](https://codeforces.com/problemset/problem/590/B) + +### Parallel Binary Search + +* [Szkopul - Meteors](https://szkopul.edu.pl/problemset/problem/7JrCYZ7LhEK4nBR5zbAXpcmM/site/?key=statement) +* [AtCoder - Stamp Rally](https://atcoder.jp/contests/agc002/tasks/agc002_d) + + +[^1]: Note that this section is following the description in [Sports programming in practice](https://kostka.dev/sp/). \ No newline at end of file From d2a381031eaf5d844c98f1cd30127179be82dcaf Mon Sep 17 00:00:00 2001 From: Bartosz Kostka Date: Sat, 26 Oct 2024 23:09:57 -0400 Subject: [PATCH 02/10] Small fixes. --- src/num_methods/binary_search.md | 129 +++++++------------------------ 1 file changed, 28 insertions(+), 101 deletions(-) diff --git a/src/num_methods/binary_search.md b/src/num_methods/binary_search.md index 0fab8c947..67b9b19e7 100644 --- a/src/num_methods/binary_search.md +++ b/src/num_methods/binary_search.md @@ -71,7 +71,7 @@ while (r - l > 1) { 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). -**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. +**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. ## Search on arbitrary predicate @@ -138,126 +138,56 @@ Another noteworthy way to do binary search is, instead of maintaining an active 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. -## Parallel Binary Search +## Parallel Binary Search -[^1] 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. +Note that this section is following the description in [Sports programming in practice](https://kostka.dev/sp/). -Specifally, let us consider the following array $A$: - -| $A_0$ | $A_1$ | $A_2$ | $A_3$ | $A_4$ | $A_5$ | $A_6$ | $A_7$ | -|-------|-------|-------|-------|-------|-------|-------|-------| -| 1 | 3 | 5 | 7 | 9 | 9 | 13 | 15 | +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. +Specifally, let us consider the following array $A = [1,3,5,7,9,9,13,15]$ with queries: $X = [8,11,4,5]$. We can use binary search for each query sequentially. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
query$ X_1 = 8 $$ X_2 = 11 $$ X_3 = 4 $$ X_4 = 5 $
step 1answer in $[0,7]$answer in $[0,7]$answer in $[0,7]$answer in $[0,7]$
check $ A_4 $check $ A_4 $check $ A_4 $check $ A_4 $
$ X_1 < A_4 = 9 $$ X_2 \geq A_4 = 9 $$ X_3 < A_4 = 9 $$ X_4 < A_4 = 9 $
step 2answer in $[0,3]$answer in $[4,7]$answer in $[0,3]$answer in $[0,3]$
check $ A_2 $check $ A_6 $check $ A_2 $check $ A_2 $
$ X_1 \geq A_2 = 5 $$ X_2 < A_6 = 13 $$ X_3 < A_2 = 5 $$ X_4 \geq A_2 = 5 $
step 3answer in $[2,3]$answer in $[4,5]$answer in $[0,1]$answer in $[2,3]$
check $ A_3 $check $ A_5 $check $ A_1 $check $ A_3 $
$ X_1 \geq A_3 = 7 $$ X_2 \geq A_5 = 9 $$ X_3 \geq A_1 = 3 $$ X_4 < A_3 = 7 $
step 4answer in $[3,3]$answer in $[5,5]$answer in $[1,1]$answer in $[2,2]$
$ index = 3 $$ index = 5 $$ index = 1 $$ index = 2 $
- +| query | \( X_1 = 8 \) | \( X_2 = 11 \) | \( X_3 = 4 \) | \( X_4 = 5 \) | +|--------|------------------------|------------------------|-----------------------|-----------------------| +| **step 1** | answer in \([0,8)\) | answer in \([0,8)\) | answer in \([0,8)\) | answer in \([0,8)\) | +| | check \( A_4 \) | check \( A_4 \) | check \( A_4 \) | check \( A_4 \) | +| | \( X_1 < A_4 = 9 \) | \( X_2 \geq A_4 = 9 \) | \( X_3 < A_4 = 9 \) | \( X_4 < A_4 = 9 \) | +| **step 2** | answer in \([0,4)\) | answer in \([4,8)\) | answer in \([0,4)\) | answer in \([0,4)\) | +| | check \( A_2 \) | check \( A_6 \) | check \( A_2 \) | check \( A_2 \) | +| | \( X_1 \geq A_2 = 5 \) | \( X_2 < A_6 = 13 \) | \( X_3 < A_2 = 5 \) | \( X_4 \geq A_2 = 5 \) | +| **step 3** | answer in \([2,4)\) | answer in \([4,6)\) | answer in \([0,2)\) | answer in \([2,4)\) | +| | check \( A_3 \) | check \( A_5 \) | check \( A_1 \) | check \( A_3 \) | +| | \( X_1 \geq A_3 = 7 \) | \( X_2 \geq A_5 = 9 \) | \( X_3 \geq A_1 = 3 \) | \( X_4 < A_3 = 7 \) | +| **step 4** | answer in \([3,4)\) | answer in \([5,6)\) | answer in \([1,2)\) | answer in \([2,3)\) | +| | \( index = 3 \) | \( index = 5 \) | \( index = 1 \) | \( index = 2 \) | 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. -```cpp +```{.cpp file=parallel-binary-search} // Computes the index of the largest value in table A less than or equal to $X_i$ for all $i$. vector ParallelBinarySearch(vector& A, vector& X) { int N = A.size(); int M = X.size(); - vector P(M, -1); - vector Q(M, N-1); + vector left(M, -1); + vector right(M, N-1); for (int step = 1; step <= ceil(log2(N)); ++step) { // Map to store indices of queries asking for this value. - unordered_map> important_values; + unordered_map> mid_to_queries; // Calculate mid and populate the important_values map. for (int i = 0; i < M; ++i) { - int mid = (P[i] + Q[i]) / 2; - important_values[mid].push_back(i); + int mid = (left[i] + right[i]) / 2; + mid_to_queries[mid].push_back(i); } // Process each value in important_values. - for (const auto& [mid, queries]: important_values) { + for (const auto& [mid, queries]: mid_to_queries) { for (int query : queries) { if (A[mid] > X[query]) { - Q[query] = mid; + right[query] = mid; } else { - P[query] = mid; + left[query] = mid; } } } @@ -286,7 +216,4 @@ vector ParallelBinarySearch(vector& A, vector& X) { ### Parallel Binary Search * [Szkopul - Meteors](https://szkopul.edu.pl/problemset/problem/7JrCYZ7LhEK4nBR5zbAXpcmM/site/?key=statement) -* [AtCoder - Stamp Rally](https://atcoder.jp/contests/agc002/tasks/agc002_d) - - -[^1]: Note that this section is following the description in [Sports programming in practice](https://kostka.dev/sp/). \ No newline at end of file +* [AtCoder - Stamp Rally](https://atcoder.jp/contests/agc002/tasks/agc002_d) \ No newline at end of file From 2f5e0bffa2397d83c55701d24e281f568b0ee9de Mon Sep 17 00:00:00 2001 From: Bartosz Kostka Date: Sat, 26 Oct 2024 23:11:01 -0400 Subject: [PATCH 03/10] Remove latex in comments. --- src/num_methods/binary_search.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/num_methods/binary_search.md b/src/num_methods/binary_search.md index 67b9b19e7..9883dee17 100644 --- a/src/num_methods/binary_search.md +++ b/src/num_methods/binary_search.md @@ -164,7 +164,7 @@ with queries: $X = [8,11,4,5]$. We can use binary search for each query sequenti 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. ```{.cpp file=parallel-binary-search} -// Computes the index of the largest value in table A less than or equal to $X_i$ for all $i$. +// Computes the index of the largest value in table A less than or equal to X_i for all i. vector ParallelBinarySearch(vector& A, vector& X) { int N = A.size(); int M = X.size(); From 9cb53f397b079765870476f87d9ecdbe6558855e Mon Sep 17 00:00:00 2001 From: Bartosz Kostka Date: Sat, 26 Oct 2024 23:15:34 -0400 Subject: [PATCH 04/10] Fix naming in comments. --- src/num_methods/binary_search.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/num_methods/binary_search.md b/src/num_methods/binary_search.md index 9883dee17..fa706c23b 100644 --- a/src/num_methods/binary_search.md +++ b/src/num_methods/binary_search.md @@ -175,13 +175,13 @@ vector ParallelBinarySearch(vector& A, vector& X) { // Map to store indices of queries asking for this value. unordered_map> mid_to_queries; - // Calculate mid and populate the important_values map. + // Calculate mid and populate the mid_to_queries map. for (int i = 0; i < M; ++i) { int mid = (left[i] + right[i]) / 2; mid_to_queries[mid].push_back(i); } - // Process each value in important_values. + // Process each value in mid_to_queries. for (const auto& [mid, queries]: mid_to_queries) { for (int query : queries) { if (A[mid] > X[query]) { From 5b4e4df766a88b60fa33b79e91265e86aa108fe1 Mon Sep 17 00:00:00 2001 From: Bartosz Kostka Date: Sat, 26 Oct 2024 23:16:56 -0400 Subject: [PATCH 05/10] Unify sides in conditions. --- src/num_methods/binary_search.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/num_methods/binary_search.md b/src/num_methods/binary_search.md index fa706c23b..77666b3e8 100644 --- a/src/num_methods/binary_search.md +++ b/src/num_methods/binary_search.md @@ -184,7 +184,7 @@ vector ParallelBinarySearch(vector& A, vector& X) { // Process each value in mid_to_queries. for (const auto& [mid, queries]: mid_to_queries) { for (int query : queries) { - if (A[mid] > X[query]) { + if (X[query] < A[mid]>) { right[query] = mid; } else { left[query] = mid; From c1cccdd5a81686de540db95065c1259160f0f394 Mon Sep 17 00:00:00 2001 From: Bartosz Kostka Date: Sat, 26 Oct 2024 23:17:05 -0400 Subject: [PATCH 06/10] Typo. --- src/num_methods/binary_search.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/num_methods/binary_search.md b/src/num_methods/binary_search.md index 77666b3e8..6c0d1ceb5 100644 --- a/src/num_methods/binary_search.md +++ b/src/num_methods/binary_search.md @@ -184,7 +184,7 @@ vector ParallelBinarySearch(vector& A, vector& X) { // Process each value in mid_to_queries. for (const auto& [mid, queries]: mid_to_queries) { for (int query : queries) { - if (X[query] < A[mid]>) { + if (X[query] < A[mid]) { right[query] = mid; } else { left[query] = mid; From 994c1f2fbbd3742981b8644f345917edae8c9d58 Mon Sep 17 00:00:00 2001 From: Bartosz Kostka Date: Sat, 26 Oct 2024 23:18:08 -0400 Subject: [PATCH 07/10] Tenses. --- src/num_methods/binary_search.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/num_methods/binary_search.md b/src/num_methods/binary_search.md index 6c0d1ceb5..f45214a83 100644 --- a/src/num_methods/binary_search.md +++ b/src/num_methods/binary_search.md @@ -140,7 +140,7 @@ This paradigm is widely used in tasks around trees, such as finding lowest commo ## Parallel Binary Search -Note that this section is following the description in [Sports programming in practice](https://kostka.dev/sp/). +Note that this section follows the description in [Sports programming in practice](https://kostka.dev/sp/). 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. From 56e78407aa67bd9ee444ab6057a04b1509fa0d5e Mon Sep 17 00:00:00 2001 From: Bartosz Kostka Date: Sun, 27 Oct 2024 04:16:50 +0000 Subject: [PATCH 08/10] Some fixes. --- src/num_methods/binary_search.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/num_methods/binary_search.md b/src/num_methods/binary_search.md index f45214a83..55be79f61 100644 --- a/src/num_methods/binary_search.md +++ b/src/num_methods/binary_search.md @@ -142,9 +142,9 @@ This paradigm is widely used in tasks around trees, such as finding lowest commo Note that this section follows the description in [Sports programming in practice](https://kostka.dev/sp/). -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. +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 a sorted 0-indexed array $A$. Naturally, each query can be answered using binary search. -Specifally, let us consider the following array $A = [1,3,5,7,9,9,13,15]$ +Specifically, let us consider the following array $A = [1,3,5,7,9,9,13,15]$ with queries: $X = [8,11,4,5]$. We can use binary search for each query sequentially. | query | \( X_1 = 8 \) | \( X_2 = 11 \) | \( X_3 = 4 \) | \( X_4 = 5 \) | @@ -161,11 +161,11 @@ with queries: $X = [8,11,4,5]$. We can use binary search for each query sequenti | **step 4** | answer in \([3,4)\) | answer in \([5,6)\) | answer in \([1,2)\) | answer in \([2,3)\) | | | \( index = 3 \) | \( index = 5 \) | \( index = 1 \) | \( index = 2 \) | -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. +We generally process this table by columns (queries), but notice that in each row we often repeat access to certain values of the array. To limit access to these 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. ```{.cpp file=parallel-binary-search} -// Computes the index of the largest value in table A less than or equal to X_i for all i. -vector ParallelBinarySearch(vector& A, vector& X) { +// Computes the index of the largest value in a sorted array A less than or equal to X_i for all i. +vector parallel_binary_search(vector& A, vector& X) { int N = A.size(); int M = X.size(); vector left(M, -1); @@ -192,7 +192,7 @@ vector ParallelBinarySearch(vector& A, vector& X) { } } } - return P; + return left; } ``` From 8629e6ed9e6d6428b56c21964def82ee3e5cfeb5 Mon Sep 17 00:00:00 2001 From: Bartosz Kostka Date: Sun, 27 Oct 2024 04:24:09 +0000 Subject: [PATCH 09/10] Fixes 2. --- src/num_methods/binary_search.md | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/num_methods/binary_search.md b/src/num_methods/binary_search.md index 55be79f61..fd0bf2385 100644 --- a/src/num_methods/binary_search.md +++ b/src/num_methods/binary_search.md @@ -168,31 +168,30 @@ We generally process this table by columns (queries), but notice that in each ro vector parallel_binary_search(vector& A, vector& X) { int N = A.size(); int M = X.size(); - vector left(M, -1); - vector right(M, N-1); + vector l(M, -1), r(M, N-1); for (int step = 1; step <= ceil(log2(N)); ++step) { // Map to store indices of queries asking for this value. - unordered_map> mid_to_queries; + unordered_map> m_to_queries; - // Calculate mid and populate the mid_to_queries map. + // Calculate middle point and populate the m_to_queries map. for (int i = 0; i < M; ++i) { - int mid = (left[i] + right[i]) / 2; - mid_to_queries[mid].push_back(i); + int m = (l[i] + r[i]) / 2; + m_to_queries[m].push_back(i); } - // Process each value in mid_to_queries. - for (const auto& [mid, queries]: mid_to_queries) { + // Process each value in m_to_queries. + for (const auto& [m, queries]: m_to_queries) { for (int query : queries) { - if (X[query] < A[mid]) { - right[query] = mid; + if (X[query] < A[m]) { + r[query] = m; } else { - left[query] = mid; + l[query] = m; } } } } - return left; + return l; } ``` From 5d87760d985c9152bae39016a4ec1c82a9791bac Mon Sep 17 00:00:00 2001 From: Bartosz Kostka Date: Sun, 27 Oct 2024 04:25:25 +0000 Subject: [PATCH 10/10] N-1 to N. --- src/num_methods/binary_search.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/num_methods/binary_search.md b/src/num_methods/binary_search.md index fd0bf2385..72b71383c 100644 --- a/src/num_methods/binary_search.md +++ b/src/num_methods/binary_search.md @@ -168,7 +168,7 @@ We generally process this table by columns (queries), but notice that in each ro vector parallel_binary_search(vector& A, vector& X) { int N = A.size(); int M = X.size(); - vector l(M, -1), r(M, N-1); + vector l(M, -1), r(M, N); for (int step = 1; step <= ceil(log2(N)); ++step) { // Map to store indices of queries asking for this value.