From bdf87af043443dc0639be478a00c37baff53fb02 Mon Sep 17 00:00:00 2001 From: freakin23 Date: Fri, 7 Feb 2025 14:31:08 +0530 Subject: [PATCH 01/17] add c++ solution for Sleepy cow Sorting --- solutions/gold/usaco-898.mdx | 196 ++++++++++++++++++++++++++++++++++- 1 file changed, 195 insertions(+), 1 deletion(-) diff --git a/solutions/gold/usaco-898.mdx b/solutions/gold/usaco-898.mdx index 1771d74929..53b66155d2 100644 --- a/solutions/gold/usaco-898.mdx +++ b/solutions/gold/usaco-898.mdx @@ -19,6 +19,139 @@ Note: The video solution might not be the same as other solutions. Code in C++. ### Using Segment Tree + + +```cpp +#include +#include +#include + +// BeginCodeSnip{Segment Tree} +template +struct SegmentTree { + using monoid = typename T::monoid; + + explicit SegmentTree(const int n) + : SegmentTree(std::vector(n, T::id())) {} + + explicit SegmentTree(const std::vector& a) : n(a.size()), p2(1) { + while (p2 < n) { + p2 <<= 1; + } + data.assign(p2 << 1, T::id()); + std::copy(a.begin(), a.end(), data.begin() + p2); + for (int i = p2 - 1; i > 0; --i) { + data[i] = T::merge(data[i << 1], data[(i << 1) + 1]); + } + } + + void set(int idx, const monoid val) { + idx += p2; + data[idx] = val; + while (idx >>= 1) { + data[idx] = T::merge(data[idx << 1], data[(idx << 1) + 1]); + } + } + + monoid get(int left, int right) const { + monoid res_l = T::id(), res_r = T::id(); + for (left += p2, right += p2; left < right; left >>= 1, right >>= 1) { + if (left & 1) { + res_l = T::merge(res_l, data[left++]); + } + if (right & 1) { + res_r = T::merge(data[--right], res_r); + } + } + return T::merge(res_l, res_r); + } + + monoid operator[](const int idx) const { return data[idx + p2]; } + + private: + const int n; + int p2; + std::vector data; +}; + +namespace monoid { + template + struct RangeSumQuery { + using monoid = T; + static constexpr monoid id() { return 0; } + static monoid merge(const monoid& a, const monoid& b) { return a + b; } + }; +} +// EndCodeSnip + +void set_up(std::string name) { + freopen((name + ".in").c_str(), "r", stdin); + freopen((name + ".out").c_str(), "w", stdout); +} + +int main() { + set_up("sleepy"); + int n; + std::cin >> n; + std::vector cows(n); + for (auto &x : cows) { + std::cin >> x; + x--; + } + + /* + * To find K, we first need to calculate the length of the longest + * suffix of the array that is already in order. + * + * Then, we can subtract that length from N to get K + * + * Read the analysis of the bronze version of this problem to learn why + * this is the case: + * http://www.usaco.org/current/data/sol_sleepy_bronze_jan19.html + */ + + int suffix_length = 1; + for (int i = n - 1; i > 0; i--) { + // If current cow is in order, increment suffix length and continue + // Otherwise, there has been an inversion so we break from the loop + if (cows[i] > cows[i - 1]) { + suffix_length++; + } else { + break; + } + } + + int k = n - suffix_length; + std::cout << k << '\n'; + + /* To calculate the minimum amount of paces each cow needs to make, + * we first need to find the number of cows in the sorted region that + * are smaller than that cow (this is done through a segment tree). + * + * Then, we can add that to the number of cows that the cow has to move + * through to reach the sorted region of the array, or in other words, + * the number of cows to the right of the current cow that are in the + * unsorted region of the array. + */ + + SegmentTree> seg(n); + for (int i = k; i < n; i++) { + seg.set(cows[i], 1); + } + + for (int i = 0; i < k; i++) { + // Takes the prefix sum up to cows[i] - 1, which calculates the + // number of cows smaller than the current cow + int smaller = seg.get(0, cows[i]); + + std::cout << smaller + (k - i - 1) << " \n"[i == k - 1]; + seg.set(cows[i], 1); + } +} + +``` + + ```java @@ -46,7 +179,7 @@ public class Sleepy { */ int suffixLength = 1; - for (int i = n - 1; i >= 0; i--) { + for (int i = n - 1; i > 0; i--) { // If current cow is in order, increment suffix length and continue // Otherwise, there has been an inversion so we break from the loop if (cows[i] > cows[i - 1]) { @@ -122,6 +255,67 @@ public class Sleepy { ### Using Binary Indexed Tree + + +```cpp +#include +#include + +// BeginCodeSnip{Binary Indexed Tree} +struct BIT { + const int n; + std::vector bit; + BIT(int n) : n(n), bit(n, 0) {} + + void add(int x, int v) { + for (int i = x; i <= n; i += i & -i) { + bit[i] += v; + } + } + + int query(int x) { + int res = 0; + for (int i = x; i > 0; i -= i & -i) { + res += bit[i]; + } + return res; + } +}; +// EndCodeSnip + +void set_up(std::string name) { + freopen((name + ".in").c_str(), "r", stdin); + freopen((name + ".out").c_str(), "w", stdout); +} + +int main() { + set_up("sleepy"); + int n; + std::cin >> n; + std::vector cows(n + 1); + for (int i = 1; i <= n; i++) { + std::cin >> cows[i]; + } + + int k = n; + BIT bit(n + 1); + while (cows[k] > cows[k - 1]) { + bit.add(cows[k], 1); + k--; + } + + bit.add(cows[k], 1); + k--; + + std::cout << k << '\n'; + for (int i = 1; i <= k; i++) { + std::cout << bit.query(cows[i] - 1) + k - i << " \n"[i == k]; + bit.add(cows[i], 1); + } +} +``` + + ```java From db743133240095f8fe3db92c68a01b6ae1f2bf5f Mon Sep 17 00:00:00 2001 From: freakin23 Date: Fri, 7 Feb 2025 14:32:03 +0530 Subject: [PATCH 02/17] add editorial language --- solutions/gold/usaco-898.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solutions/gold/usaco-898.mdx b/solutions/gold/usaco-898.mdx index 53b66155d2..b30fef2562 100644 --- a/solutions/gold/usaco-898.mdx +++ b/solutions/gold/usaco-898.mdx @@ -5,7 +5,7 @@ title: Sleepy Cow Sorting author: Nathan Gong, Melody Yu (Video), Qi Wang, Daniel Ge --- -[Official Analysis](http://www.usaco.org/current/data/sol_sleepy_gold_jan19.html) +[Official Analysis (C++)](http://www.usaco.org/current/data/sol_sleepy_gold_jan19.html) ## Video Solution From 845a2cf3b3ed2cad34e71df169d197239f7f1d91 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 7 Feb 2025 09:05:05 +0000 Subject: [PATCH 03/17] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- solutions/gold/usaco-898.mdx | 290 ++++++++++++++++------------------- 1 file changed, 136 insertions(+), 154 deletions(-) diff --git a/solutions/gold/usaco-898.mdx b/solutions/gold/usaco-898.mdx index b30fef2562..2ebe3a99ef 100644 --- a/solutions/gold/usaco-898.mdx +++ b/solutions/gold/usaco-898.mdx @@ -22,133 +22,121 @@ Note: The video solution might not be the same as other solutions. Code in C++. ```cpp +#include #include #include -#include // BeginCodeSnip{Segment Tree} -template -struct SegmentTree { - using monoid = typename T::monoid; - - explicit SegmentTree(const int n) - : SegmentTree(std::vector(n, T::id())) {} - - explicit SegmentTree(const std::vector& a) : n(a.size()), p2(1) { - while (p2 < n) { - p2 <<= 1; - } - data.assign(p2 << 1, T::id()); - std::copy(a.begin(), a.end(), data.begin() + p2); - for (int i = p2 - 1; i > 0; --i) { - data[i] = T::merge(data[i << 1], data[(i << 1) + 1]); - } - } - - void set(int idx, const monoid val) { - idx += p2; - data[idx] = val; - while (idx >>= 1) { - data[idx] = T::merge(data[idx << 1], data[(idx << 1) + 1]); - } - } - - monoid get(int left, int right) const { - monoid res_l = T::id(), res_r = T::id(); - for (left += p2, right += p2; left < right; left >>= 1, right >>= 1) { - if (left & 1) { - res_l = T::merge(res_l, data[left++]); - } - if (right & 1) { - res_r = T::merge(data[--right], res_r); - } - } - return T::merge(res_l, res_r); - } - - monoid operator[](const int idx) const { return data[idx + p2]; } - - private: - const int n; - int p2; - std::vector data; +template struct SegmentTree { + using monoid = typename T::monoid; + + explicit SegmentTree(const int n) : SegmentTree(std::vector(n, T::id())) {} + + explicit SegmentTree(const std::vector &a) : n(a.size()), p2(1) { + while (p2 < n) { p2 <<= 1; } + data.assign(p2 << 1, T::id()); + std::copy(a.begin(), a.end(), data.begin() + p2); + for (int i = p2 - 1; i > 0; --i) { + data[i] = T::merge(data[i << 1], data[(i << 1) + 1]); + } + } + + void set(int idx, const monoid val) { + idx += p2; + data[idx] = val; + while (idx >>= 1) { + data[idx] = T::merge(data[idx << 1], data[(idx << 1) + 1]); + } + } + + monoid get(int left, int right) const { + monoid res_l = T::id(), res_r = T::id(); + for (left += p2, right += p2; left < right; left >>= 1, right >>= 1) { + if (left & 1) { res_l = T::merge(res_l, data[left++]); } + if (right & 1) { res_r = T::merge(data[--right], res_r); } + } + return T::merge(res_l, res_r); + } + + monoid operator[](const int idx) const { return data[idx + p2]; } + + private: + const int n; + int p2; + std::vector data; }; namespace monoid { - template - struct RangeSumQuery { - using monoid = T; - static constexpr monoid id() { return 0; } - static monoid merge(const monoid& a, const monoid& b) { return a + b; } - }; -} +template struct RangeSumQuery { + using monoid = T; + static constexpr monoid id() { return 0; } + static monoid merge(const monoid &a, const monoid &b) { return a + b; } +}; +} // namespace monoid // EndCodeSnip void set_up(std::string name) { - freopen((name + ".in").c_str(), "r", stdin); - freopen((name + ".out").c_str(), "w", stdout); + freopen((name + ".in").c_str(), "r", stdin); + freopen((name + ".out").c_str(), "w", stdout); } int main() { - set_up("sleepy"); - int n; - std::cin >> n; - std::vector cows(n); - for (auto &x : cows) { - std::cin >> x; - x--; - } - - /* - * To find K, we first need to calculate the length of the longest - * suffix of the array that is already in order. - * - * Then, we can subtract that length from N to get K - * - * Read the analysis of the bronze version of this problem to learn why - * this is the case: - * http://www.usaco.org/current/data/sol_sleepy_bronze_jan19.html - */ - - int suffix_length = 1; - for (int i = n - 1; i > 0; i--) { - // If current cow is in order, increment suffix length and continue + set_up("sleepy"); + int n; + std::cin >> n; + std::vector cows(n); + for (auto &x : cows) { + std::cin >> x; + x--; + } + + /* + * To find K, we first need to calculate the length of the longest + * suffix of the array that is already in order. + * + * Then, we can subtract that length from N to get K + * + * Read the analysis of the bronze version of this problem to learn why + * this is the case: + * http://www.usaco.org/current/data/sol_sleepy_bronze_jan19.html + */ + + int suffix_length = 1; + for (int i = n - 1; i > 0; i--) { + // If current cow is in order, increment suffix length and continue // Otherwise, there has been an inversion so we break from the loop - if (cows[i] > cows[i - 1]) { - suffix_length++; - } else { - break; - } - } - - int k = n - suffix_length; - std::cout << k << '\n'; - - /* To calculate the minimum amount of paces each cow needs to make, - * we first need to find the number of cows in the sorted region that - * are smaller than that cow (this is done through a segment tree). - * - * Then, we can add that to the number of cows that the cow has to move - * through to reach the sorted region of the array, or in other words, - * the number of cows to the right of the current cow that are in the - * unsorted region of the array. - */ - - SegmentTree> seg(n); - for (int i = k; i < n; i++) { - seg.set(cows[i], 1); - } - - for (int i = 0; i < k; i++) { - // Takes the prefix sum up to cows[i] - 1, which calculates the - // number of cows smaller than the current cow - int smaller = seg.get(0, cows[i]); - - std::cout << smaller + (k - i - 1) << " \n"[i == k - 1]; - seg.set(cows[i], 1); - } -} + if (cows[i] > cows[i - 1]) { + suffix_length++; + } else { + break; + } + } + int k = n - suffix_length; + std::cout << k << '\n'; + + /* To calculate the minimum amount of paces each cow needs to make, + * we first need to find the number of cows in the sorted region that + * are smaller than that cow (this is done through a segment tree). + * + * Then, we can add that to the number of cows that the cow has to move + * through to reach the sorted region of the array, or in other words, + * the number of cows to the right of the current cow that are in the + * unsorted region of the array. + */ + + SegmentTree> seg(n); + for (int i = k; i < n; i++) { seg.set(cows[i], 1); } + + for (int i = 0; i < k; i++) { + // Takes the prefix sum up to cows[i] - 1, which calculates the + // number of cows smaller than the current cow + int smaller = seg.get(0, cows[i]); + + std::cout << smaller + (k - i - 1) << " \n"[i == k - 1]; + seg.set(cows[i], 1); + } +} ``` @@ -263,55 +251,49 @@ public class Sleepy { // BeginCodeSnip{Binary Indexed Tree} struct BIT { - const int n; - std::vector bit; - BIT(int n) : n(n), bit(n, 0) {} - - void add(int x, int v) { - for (int i = x; i <= n; i += i & -i) { - bit[i] += v; - } - } - - int query(int x) { - int res = 0; - for (int i = x; i > 0; i -= i & -i) { - res += bit[i]; - } - return res; - } + const int n; + std::vector bit; + BIT(int n) : n(n), bit(n, 0) {} + + void add(int x, int v) { + for (int i = x; i <= n; i += i & -i) { bit[i] += v; } + } + + int query(int x) { + int res = 0; + for (int i = x; i > 0; i -= i & -i) { res += bit[i]; } + return res; + } }; // EndCodeSnip void set_up(std::string name) { - freopen((name + ".in").c_str(), "r", stdin); - freopen((name + ".out").c_str(), "w", stdout); + freopen((name + ".in").c_str(), "r", stdin); + freopen((name + ".out").c_str(), "w", stdout); } int main() { - set_up("sleepy"); - int n; - std::cin >> n; - std::vector cows(n + 1); - for (int i = 1; i <= n; i++) { - std::cin >> cows[i]; - } - - int k = n; - BIT bit(n + 1); - while (cows[k] > cows[k - 1]) { - bit.add(cows[k], 1); - k--; - } - - bit.add(cows[k], 1); - k--; - - std::cout << k << '\n'; - for (int i = 1; i <= k; i++) { - std::cout << bit.query(cows[i] - 1) + k - i << " \n"[i == k]; - bit.add(cows[i], 1); - } + set_up("sleepy"); + int n; + std::cin >> n; + std::vector cows(n + 1); + for (int i = 1; i <= n; i++) { std::cin >> cows[i]; } + + int k = n; + BIT bit(n + 1); + while (cows[k] > cows[k - 1]) { + bit.add(cows[k], 1); + k--; + } + + bit.add(cows[k], 1); + k--; + + std::cout << k << '\n'; + for (int i = 1; i <= k; i++) { + std::cout << bit.query(cows[i] - 1) + k - i << " \n"[i == k]; + bit.add(cows[i], 1); + } } ``` From 452375d2f35d1c6da3d2d03343af80653e426016 Mon Sep 17 00:00:00 2001 From: Rameez Parwez <79394137+Sosuke23@users.noreply.github.com> Date: Fri, 7 Feb 2025 14:36:51 +0530 Subject: [PATCH 04/17] Update usaco-898.mdx --- solutions/gold/usaco-898.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solutions/gold/usaco-898.mdx b/solutions/gold/usaco-898.mdx index 2ebe3a99ef..8a4dbe8d23 100644 --- a/solutions/gold/usaco-898.mdx +++ b/solutions/gold/usaco-898.mdx @@ -72,7 +72,7 @@ template struct RangeSumQuery { static constexpr monoid id() { return 0; } static monoid merge(const monoid &a, const monoid &b) { return a + b; } }; -} // namespace monoid +} // EndCodeSnip void set_up(std::string name) { From 464260a5d459204f2569c85d9c330919dfa04f2d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 7 Feb 2025 09:08:06 +0000 Subject: [PATCH 05/17] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- solutions/gold/usaco-898.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solutions/gold/usaco-898.mdx b/solutions/gold/usaco-898.mdx index 8a4dbe8d23..2ebe3a99ef 100644 --- a/solutions/gold/usaco-898.mdx +++ b/solutions/gold/usaco-898.mdx @@ -72,7 +72,7 @@ template struct RangeSumQuery { static constexpr monoid id() { return 0; } static monoid merge(const monoid &a, const monoid &b) { return a + b; } }; -} +} // namespace monoid // EndCodeSnip void set_up(std::string name) { From b132df27f3f433b0db29130f405def53b424ba53 Mon Sep 17 00:00:00 2001 From: freakin23 Date: Fri, 7 Feb 2025 21:52:44 +0530 Subject: [PATCH 06/17] update segment template --- solutions/gold/usaco-898.mdx | 82 ++++++++++++------------------------ 1 file changed, 26 insertions(+), 56 deletions(-) diff --git a/solutions/gold/usaco-898.mdx b/solutions/gold/usaco-898.mdx index b30fef2562..79fcd0906e 100644 --- a/solutions/gold/usaco-898.mdx +++ b/solutions/gold/usaco-898.mdx @@ -27,61 +27,32 @@ Note: The video solution might not be the same as other solutions. Code in C++. #include // BeginCodeSnip{Segment Tree} -template -struct SegmentTree { - using monoid = typename T::monoid; - - explicit SegmentTree(const int n) - : SegmentTree(std::vector(n, T::id())) {} - - explicit SegmentTree(const std::vector& a) : n(a.size()), p2(1) { - while (p2 < n) { - p2 <<= 1; - } - data.assign(p2 << 1, T::id()); - std::copy(a.begin(), a.end(), data.begin() + p2); - for (int i = p2 - 1; i > 0; --i) { - data[i] = T::merge(data[i << 1], data[(i << 1) + 1]); - } - } - - void set(int idx, const monoid val) { - idx += p2; - data[idx] = val; - while (idx >>= 1) { - data[idx] = T::merge(data[idx << 1], data[(idx << 1) + 1]); +template class SumSegmentTree { + private: + const T DEFAULT = 0; + std::vector segtree; + int len; + + public: + SumSegmentTree(int len) : len(len), segtree(len * 2, DEFAULT) {} + + void set(int ind, T val) { + ind += len; + segtree[ind] = val; + for (; ind > 1; ind /= 2) { + segtree[ind / 2] = segtree[ind] + segtree[ind ^ 1]; } } - - monoid get(int left, int right) const { - monoid res_l = T::id(), res_r = T::id(); - for (left += p2, right += p2; left < right; left >>= 1, right >>= 1) { - if (left & 1) { - res_l = T::merge(res_l, data[left++]); - } - if (right & 1) { - res_r = T::merge(data[--right], res_r); - } + + T range_sum(int start, int end) { + T sum = DEFAULT; + for (start += len, end += len; start < end; start /= 2, end /= 2) { + if (start % 2 == 1) { sum += segtree[start++]; } + if (end % 2 == 1) { sum += segtree[--end]; } } - return T::merge(res_l, res_r); + return sum; } - - monoid operator[](const int idx) const { return data[idx + p2]; } - - private: - const int n; - int p2; - std::vector data; }; - -namespace monoid { - template - struct RangeSumQuery { - using monoid = T; - static constexpr monoid id() { return 0; } - static monoid merge(const monoid& a, const monoid& b) { return a + b; } - }; -} // EndCodeSnip void set_up(std::string name) { @@ -107,7 +78,7 @@ int main() { * * Read the analysis of the bronze version of this problem to learn why * this is the case: - * http://www.usaco.org/current/data/sol_sleepy_bronze_jan19.html + * http://www.usaco.org/current/dataa/sol_sleepy_bronze_jan19.html */ int suffix_length = 1; @@ -134,21 +105,20 @@ int main() { * unsorted region of the array. */ - SegmentTree> seg(n); + SumSegmentTree segtree(n); for (int i = k; i < n; i++) { - seg.set(cows[i], 1); + segtree.set(cows[i], 1); } for (int i = 0; i < k; i++) { // Takes the prefix sum up to cows[i] - 1, which calculates the // number of cows smaller than the current cow - int smaller = seg.get(0, cows[i]); + int smaller = segtree.range_sum(0, cows[i]); std::cout << smaller + (k - i - 1) << " \n"[i == k - 1]; - seg.set(cows[i], 1); + segtree.set(cows[i], 1); } } - ``` From f7710e28c542c409ab2c744e20e77eac9daa2602 Mon Sep 17 00:00:00 2001 From: freakin23 Date: Fri, 7 Feb 2025 21:56:21 +0530 Subject: [PATCH 07/17] update BIT template --- solutions/gold/usaco-898.mdx | 42 +++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/solutions/gold/usaco-898.mdx b/solutions/gold/usaco-898.mdx index 79fcd0906e..0ebf99d18a 100644 --- a/solutions/gold/usaco-898.mdx +++ b/solutions/gold/usaco-898.mdx @@ -232,23 +232,31 @@ public class Sleepy { #include // BeginCodeSnip{Binary Indexed Tree} -struct BIT { - const int n; - std::vector bit; - BIT(int n) : n(n), bit(n, 0) {} - - void add(int x, int v) { - for (int i = x; i <= n; i += i & -i) { - bit[i] += v; - } +template class BIT { + private: + int size; + std::vector bit; + std::vector arr; + + public: + BIT(int size) : size(size), bit(size + 1), arr(size) {} + + /** Sets the value at index ind to val. */ + void set(int ind, T val) { add(ind, val - arr[ind]); } + + /** Adds val to the element at index ind. */ + void add(int ind, T val) { + arr[ind] += val; + ind++; + for (; ind <= size; ind += ind & -ind) { bit[ind] += val; } } - int query(int x) { - int res = 0; - for (int i = x; i > 0; i -= i & -i) { - res += bit[i]; - } - return res; + /** @return The sum of all values in [0, ind]. */ + T pref_sum(int ind) { + ind++; + T total = 0; + for (; ind > 0; ind -= ind & -ind) { total += bit[ind]; } + return total; } }; // EndCodeSnip @@ -268,7 +276,7 @@ int main() { } int k = n; - BIT bit(n + 1); + BIT bit(n + 1); while (cows[k] > cows[k - 1]) { bit.add(cows[k], 1); k--; @@ -279,7 +287,7 @@ int main() { std::cout << k << '\n'; for (int i = 1; i <= k; i++) { - std::cout << bit.query(cows[i] - 1) + k - i << " \n"[i == k]; + std::cout << bit.pref_sum(cows[i] - 1) + k - i << " \n"[i == k]; bit.add(cows[i], 1); } } From 91d9ca661a9c14f070dbd1934002bde03ac1e462 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 7 Feb 2025 16:31:24 +0000 Subject: [PATCH 08/17] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- solutions/gold/usaco-898.mdx | 160 +++++++++++++++++------------------ 1 file changed, 79 insertions(+), 81 deletions(-) diff --git a/solutions/gold/usaco-898.mdx b/solutions/gold/usaco-898.mdx index a49aac86be..b9fbf55173 100644 --- a/solutions/gold/usaco-898.mdx +++ b/solutions/gold/usaco-898.mdx @@ -28,30 +28,30 @@ Note: The video solution might not be the same as other solutions. Code in C++. // BeginCodeSnip{Segment Tree} template class SumSegmentTree { - private: - const T DEFAULT = 0; - std::vector segtree; - int len; - - public: - SumSegmentTree(int len) : len(len), segtree(len * 2, DEFAULT) {} - - void set(int ind, T val) { - ind += len; - segtree[ind] = val; - for (; ind > 1; ind /= 2) { - segtree[ind / 2] = segtree[ind] + segtree[ind ^ 1]; - } - } - - T range_sum(int start, int end) { - T sum = DEFAULT; - for (start += len, end += len; start < end; start /= 2, end /= 2) { - if (start % 2 == 1) { sum += segtree[start++]; } - if (end % 2 == 1) { sum += segtree[--end]; } - } - return sum; - } + private: + const T DEFAULT = 0; + std::vector segtree; + int len; + + public: + SumSegmentTree(int len) : len(len), segtree(len * 2, DEFAULT) {} + + void set(int ind, T val) { + ind += len; + segtree[ind] = val; + for (; ind > 1; ind /= 2) { + segtree[ind / 2] = segtree[ind] + segtree[ind ^ 1]; + } + } + + T range_sum(int start, int end) { + T sum = DEFAULT; + for (start += len, end += len; start < end; start /= 2, end /= 2) { + if (start % 2 == 1) { sum += segtree[start++]; } + if (end % 2 == 1) { sum += segtree[--end]; } + } + return sum; + } }; // EndCodeSnip @@ -70,16 +70,16 @@ int main() { x--; } - /* - * To find K, we first need to calculate the length of the longest - * suffix of the array that is already in order. - * - * Then, we can subtract that length from N to get K - * - * Read the analysis of the bronze version of this problem to learn why - * this is the case: - * http://www.usaco.org/current/dataa/sol_sleepy_bronze_jan19.html - */ + /* + * To find K, we first need to calculate the length of the longest + * suffix of the array that is already in order. + * + * Then, we can subtract that length from N to get K + * + * Read the analysis of the bronze version of this problem to learn why + * this is the case: + * http://www.usaco.org/current/dataa/sol_sleepy_bronze_jan19.html + */ int suffix_length = 1; for (int i = n - 1; i > 0; i--) { @@ -105,19 +105,17 @@ int main() { * unsorted region of the array. */ - SumSegmentTree segtree(n); - for (int i = k; i < n; i++) { - segtree.set(cows[i], 1); - } + SumSegmentTree segtree(n); + for (int i = k; i < n; i++) { segtree.set(cows[i], 1); } - for (int i = 0; i < k; i++) { - // Takes the prefix sum up to cows[i] - 1, which calculates the - // number of cows smaller than the current cow - int smaller = segtree.range_sum(0, cows[i]); + for (int i = 0; i < k; i++) { + // Takes the prefix sum up to cows[i] - 1, which calculates the + // number of cows smaller than the current cow + int smaller = segtree.range_sum(0, cows[i]); - std::cout << smaller + (k - i - 1) << " \n"[i == k - 1]; - segtree.set(cows[i], 1); - } + std::cout << smaller + (k - i - 1) << " \n"[i == k - 1]; + segtree.set(cows[i], 1); + } } ``` @@ -233,31 +231,31 @@ public class Sleepy { // BeginCodeSnip{Binary Indexed Tree} template class BIT { - private: - int size; - std::vector bit; - std::vector arr; - - public: - BIT(int size) : size(size), bit(size + 1), arr(size) {} - - /** Sets the value at index ind to val. */ - void set(int ind, T val) { add(ind, val - arr[ind]); } - - /** Adds val to the element at index ind. */ - void add(int ind, T val) { - arr[ind] += val; - ind++; - for (; ind <= size; ind += ind & -ind) { bit[ind] += val; } - } - - /** @return The sum of all values in [0, ind]. */ - T pref_sum(int ind) { - ind++; - T total = 0; - for (; ind > 0; ind -= ind & -ind) { total += bit[ind]; } - return total; - } + private: + int size; + std::vector bit; + std::vector arr; + + public: + BIT(int size) : size(size), bit(size + 1), arr(size) {} + + /** Sets the value at index ind to val. */ + void set(int ind, T val) { add(ind, val - arr[ind]); } + + /** Adds val to the element at index ind. */ + void add(int ind, T val) { + arr[ind] += val; + ind++; + for (; ind <= size; ind += ind & -ind) { bit[ind] += val; } + } + + /** @return The sum of all values in [0, ind]. */ + T pref_sum(int ind) { + ind++; + T total = 0; + for (; ind > 0; ind -= ind & -ind) { total += bit[ind]; } + return total; + } }; // EndCodeSnip @@ -273,21 +271,21 @@ int main() { std::vector cows(n + 1); for (int i = 1; i <= n; i++) { std::cin >> cows[i]; } - int k = n; - BIT bit(n + 1); - while (cows[k] > cows[k - 1]) { - bit.add(cows[k], 1); - k--; - } + int k = n; + BIT bit(n + 1); + while (cows[k] > cows[k - 1]) { + bit.add(cows[k], 1); + k--; + } bit.add(cows[k], 1); k--; - std::cout << k << '\n'; - for (int i = 1; i <= k; i++) { - std::cout << bit.pref_sum(cows[i] - 1) + k - i << " \n"[i == k]; - bit.add(cows[i], 1); - } + std::cout << k << '\n'; + for (int i = 1; i <= k; i++) { + std::cout << bit.pref_sum(cows[i] - 1) + k - i << " \n"[i == k]; + bit.add(cows[i], 1); + } } ``` From 65dbf6723331f9e617ad43dfc3b6c1d1f2150676 Mon Sep 17 00:00:00 2001 From: freakin23 Date: Sat, 8 Feb 2025 11:13:00 +0530 Subject: [PATCH 09/17] add explanation for Seg Tree solution --- solutions/gold/usaco-898.mdx | 276 +++++++++++++++-------------------- 1 file changed, 118 insertions(+), 158 deletions(-) diff --git a/solutions/gold/usaco-898.mdx b/solutions/gold/usaco-898.mdx index b9fbf55173..7c50a5fa25 100644 --- a/solutions/gold/usaco-898.mdx +++ b/solutions/gold/usaco-898.mdx @@ -5,7 +5,7 @@ title: Sleepy Cow Sorting author: Nathan Gong, Melody Yu (Video), Qi Wang, Daniel Ge --- -[Official Analysis (C++)](http://www.usaco.org/current/data/sol_sleepy_gold_jan19.html) +[Official Analysis](http://www.usaco.org/current/data/sol_sleepy_gold_jan19.html) ## Video Solution @@ -18,104 +18,91 @@ Note: The video solution might not be the same as other solutions. Code in C++. ### Using Segment Tree +To obtain the number of cows (**K**) that are not in the correct position, subtract the length of the longest suffix of the array that is already sorted from **N**. Read the analysis of the bronze version of this problem to learn why this is the case. [Analysis](https://usaco.org/current/data/sol_sleepy_bronze_jan19.html) + +Next, for each of these unsorted cows, we calculate how many steps it needs to take to reach its correct position. To do this, we consider two things: first, we count how many cows in the sorted section have a smaller number than the cow we're focusing on. These cows are in the way and need to be bypassed. To make this counting efficient, we use a **Segment Tree** , which lets us quickly find how many smaller cows are ahead without checking each one individually. Second, we count how many cows in the unsorted section are standing to the right of the current cow, as they also block its path. + +By adding these two numbers together—the cows in the sorted section that are smaller and the cows in the unsorted section ahead of it—we get the total number of steps that cow needs to take to reach its correct spot. This way, we make sure we account for all the obstacles each cow has to pass to get to where it needs to be. + ```cpp -#include #include #include +#include +#include + +using std::vector; // BeginCodeSnip{Segment Tree} template class SumSegmentTree { - private: - const T DEFAULT = 0; - std::vector segtree; - int len; - - public: - SumSegmentTree(int len) : len(len), segtree(len * 2, DEFAULT) {} - - void set(int ind, T val) { - ind += len; - segtree[ind] = val; - for (; ind > 1; ind /= 2) { - segtree[ind / 2] = segtree[ind] + segtree[ind ^ 1]; - } - } - - T range_sum(int start, int end) { - T sum = DEFAULT; - for (start += len, end += len; start < end; start /= 2, end /= 2) { - if (start % 2 == 1) { sum += segtree[start++]; } - if (end % 2 == 1) { sum += segtree[--end]; } - } - return sum; - } + private: + const T DEFAULT = 0; + vector segtree; + int len; + + public: + SumSegmentTree(int len) : len(len), segtree(len * 2, DEFAULT) {} + + void set(int ind, T val) { + ind += len; + segtree[ind] = val; + for (; ind > 1; ind /= 2) { + segtree[ind / 2] = segtree[ind] + segtree[ind ^ 1]; + } + } + + T range_sum(int start, int end) { + T sum = DEFAULT; + for (start += len, end += len; start < end; start /= 2, end /= 2) { + if (start % 2 == 1) { sum += segtree[start++]; } + if (end % 2 == 1) { sum += segtree[--end]; } + } + return sum; + } }; // EndCodeSnip -void set_up(std::string name) { - freopen((name + ".in").c_str(), "r", stdin); - freopen((name + ".out").c_str(), "w", stdout); -} - int main() { - set_up("sleepy"); - int n; - std::cin >> n; - std::vector cows(n); - for (auto &x : cows) { - std::cin >> x; - x--; - } - - /* - * To find K, we first need to calculate the length of the longest - * suffix of the array that is already in order. - * - * Then, we can subtract that length from N to get K - * - * Read the analysis of the bronze version of this problem to learn why - * this is the case: - * http://www.usaco.org/current/dataa/sol_sleepy_bronze_jan19.html - */ - - int suffix_length = 1; - for (int i = n - 1; i > 0; i--) { - // If current cow is in order, increment suffix length and continue + std::ifstream fin("sleepy.in"); + std::ofstream fout("sleepy.out"); + + int n; + fin >> n; + vector cows(n); + for (int &x : cows) { + fin >> x; + x--; + } + + int suffix_length = 1; + for (int i = n - 1; i > 0; i--) { + // If current cow is in order, increment suffix length and continue // Otherwise, there has been an inversion so we break from the loop - if (cows[i] > cows[i - 1]) { - suffix_length++; - } else { - break; - } - } - - int k = n - suffix_length; - std::cout << k << '\n'; - - /* To calculate the minimum amount of paces each cow needs to make, - * we first need to find the number of cows in the sorted region that - * are smaller than that cow (this is done through a segment tree). - * - * Then, we can add that to the number of cows that the cow has to move - * through to reach the sorted region of the array, or in other words, - * the number of cows to the right of the current cow that are in the - * unsorted region of the array. - */ - - SumSegmentTree segtree(n); - for (int i = k; i < n; i++) { segtree.set(cows[i], 1); } - - for (int i = 0; i < k; i++) { - // Takes the prefix sum up to cows[i] - 1, which calculates the - // number of cows smaller than the current cow - int smaller = segtree.range_sum(0, cows[i]); - - std::cout << smaller + (k - i - 1) << " \n"[i == k - 1]; - segtree.set(cows[i], 1); - } + if (cows[i] > cows[i - 1]) { + suffix_length++; + } else { + break; + } + } + + int k = n - suffix_length; + fout << k << '\n'; + + SumSegmentTree segtree(n); + for (int i = k; i < n; i++) { + segtree.set(cows[i], 1); + } + + for (int i = 0; i < k; i++) { + // Takes the prefix sum up to cows[i] - 1, which calculates the + // number of cows smaller than the current cow + int smaller = segtree.range_sum(0, cows[i]); + + fout << smaller + (k - i - 1) << " \n"[i == k - 1]; + segtree.set(cows[i], 1); + } } ``` @@ -135,17 +122,6 @@ public class Sleepy { int[] cows = new int[n]; for (int i = 0; i < n; i++) { cows[i] = sc.nextInt() - 1; } - /* - * To find K, we first need to calculate the length of the longest - * suffix of the array that is already in order. - * - * Then, we can subtract that length from N to get K - * - * Read the analysis of the bronze version of this problem to learn why - * this is the case: - * http://www.usaco.org/current/data/sol_sleepy_bronze_jan19.html - */ - int suffixLength = 1; for (int i = n - 1; i > 0; i--) { // If current cow is in order, increment suffix length and continue @@ -159,16 +135,6 @@ public class Sleepy { int k = n - suffixLegth; out.println(k); - /* To calculate the minimum amount of paces each cow needs to make, - * we first need to find the number of cows in the sorted region that - * are smaller than that cow (this is done through a segment tree). - * - * Then, we can add that to the number of cows that the cow has to move - * through to reach the sorted region of the array, or in other words, - * the number of cows to the right of the current cow that are in the - * unsorted region of the array. - */ - SegmentTree seg = new SegmentTree(n); for (int i = k; i < n; i++) { seg.add(cows[i], 1); } for (int i = 0; i < k; i++) { @@ -228,64 +194,58 @@ public class Sleepy { ```cpp #include #include +#include -// BeginCodeSnip{Binary Indexed Tree} -template class BIT { - private: - int size; - std::vector bit; - std::vector arr; - - public: - BIT(int size) : size(size), bit(size + 1), arr(size) {} - - /** Sets the value at index ind to val. */ - void set(int ind, T val) { add(ind, val - arr[ind]); } - - /** Adds val to the element at index ind. */ - void add(int ind, T val) { - arr[ind] += val; - ind++; - for (; ind <= size; ind += ind & -ind) { bit[ind] += val; } - } +using std::vector; - /** @return The sum of all values in [0, ind]. */ - T pref_sum(int ind) { - ind++; - T total = 0; - for (; ind > 0; ind -= ind & -ind) { total += bit[ind]; } - return total; - } +// BeginCodeSnip{Binary Indexed Tree} +struct BIT { + const int n; + vector bit; + BIT(int n) : n(n), bit(n, 0) {} + + void add(int x, int v) { + for (int i = x; i <= n; i += i & -i) { + bit[i] += v; + } + } + + int query(int x) { + int res = 0; + for (int i = x; i > 0; i -= i & -i) { + res += bit[i]; + } + return res; + } }; // EndCodeSnip -void set_up(std::string name) { - freopen((name + ".in").c_str(), "r", stdin); - freopen((name + ".out").c_str(), "w", stdout); -} - int main() { - set_up("sleepy"); - int n; - std::cin >> n; - std::vector cows(n + 1); - for (int i = 1; i <= n; i++) { std::cin >> cows[i]; } - - int k = n; - BIT bit(n + 1); - while (cows[k] > cows[k - 1]) { - bit.add(cows[k], 1); - k--; - } - - bit.add(cows[k], 1); - k--; - - std::cout << k << '\n'; - for (int i = 1; i <= k; i++) { - std::cout << bit.pref_sum(cows[i] - 1) + k - i << " \n"[i == k]; - bit.add(cows[i], 1); - } + std::ifstream fin("sleepy.in"); + std::ofstream fout("sleepy.out"); + + int n; + fin >> n; + vector cows(n + 1); + for (int i = 1; i <= n; i++) { + fin >> cows[i]; + } + + int k = n; + BIT bit(n + 1); + while (cows[k] > cows[k - 1]) { + bit.add(cows[k], 1); + k--; + } + + bit.add(cows[k], 1); + k--; + + fout << k << '\n'; + for (int i = 1; i <= k; i++) { + fout << bit.query(cows[i] - 1) + k - i << " \n"[i == k]; + bit.add(cows[i], 1); + } } ``` From 06f55143fe261bcee75494dfd5f999be5dbc63c8 Mon Sep 17 00:00:00 2001 From: freakin23 Date: Sat, 8 Feb 2025 11:13:54 +0530 Subject: [PATCH 10/17] update dt --- solutions/gold/usaco-898.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solutions/gold/usaco-898.mdx b/solutions/gold/usaco-898.mdx index 7c50a5fa25..8c75de4b67 100644 --- a/solutions/gold/usaco-898.mdx +++ b/solutions/gold/usaco-898.mdx @@ -90,7 +90,7 @@ int main() { int k = n - suffix_length; fout << k << '\n'; - SumSegmentTree segtree(n); + SumSegmentTree segtree(n); for (int i = k; i < n; i++) { segtree.set(cows[i], 1); } From 5f153a1e9016cc80435b26e3247875b967456441 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 8 Feb 2025 05:45:15 +0000 Subject: [PATCH 11/17] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- solutions/gold/usaco-898.mdx | 204 +++++++++++++++++------------------ 1 file changed, 98 insertions(+), 106 deletions(-) diff --git a/solutions/gold/usaco-898.mdx b/solutions/gold/usaco-898.mdx index 8c75de4b67..1b2ee85715 100644 --- a/solutions/gold/usaco-898.mdx +++ b/solutions/gold/usaco-898.mdx @@ -28,81 +28,79 @@ By adding these two numbers together—the cows in the sorted section that are s ```cpp -#include -#include #include #include +#include +#include using std::vector; // BeginCodeSnip{Segment Tree} template class SumSegmentTree { - private: - const T DEFAULT = 0; - vector segtree; - int len; - - public: - SumSegmentTree(int len) : len(len), segtree(len * 2, DEFAULT) {} - - void set(int ind, T val) { - ind += len; - segtree[ind] = val; - for (; ind > 1; ind /= 2) { - segtree[ind / 2] = segtree[ind] + segtree[ind ^ 1]; - } - } - - T range_sum(int start, int end) { - T sum = DEFAULT; - for (start += len, end += len; start < end; start /= 2, end /= 2) { - if (start % 2 == 1) { sum += segtree[start++]; } - if (end % 2 == 1) { sum += segtree[--end]; } - } - return sum; - } + private: + const T DEFAULT = 0; + vector segtree; + int len; + + public: + SumSegmentTree(int len) : len(len), segtree(len * 2, DEFAULT) {} + + void set(int ind, T val) { + ind += len; + segtree[ind] = val; + for (; ind > 1; ind /= 2) { + segtree[ind / 2] = segtree[ind] + segtree[ind ^ 1]; + } + } + + T range_sum(int start, int end) { + T sum = DEFAULT; + for (start += len, end += len; start < end; start /= 2, end /= 2) { + if (start % 2 == 1) { sum += segtree[start++]; } + if (end % 2 == 1) { sum += segtree[--end]; } + } + return sum; + } }; // EndCodeSnip int main() { - std::ifstream fin("sleepy.in"); - std::ofstream fout("sleepy.out"); - - int n; - fin >> n; - vector cows(n); - for (int &x : cows) { - fin >> x; - x--; - } - - int suffix_length = 1; - for (int i = n - 1; i > 0; i--) { - // If current cow is in order, increment suffix length and continue + std::ifstream fin("sleepy.in"); + std::ofstream fout("sleepy.out"); + + int n; + fin >> n; + vector cows(n); + for (int &x : cows) { + fin >> x; + x--; + } + + int suffix_length = 1; + for (int i = n - 1; i > 0; i--) { + // If current cow is in order, increment suffix length and continue // Otherwise, there has been an inversion so we break from the loop - if (cows[i] > cows[i - 1]) { - suffix_length++; - } else { - break; - } - } - - int k = n - suffix_length; - fout << k << '\n'; - - SumSegmentTree segtree(n); - for (int i = k; i < n; i++) { - segtree.set(cows[i], 1); - } - - for (int i = 0; i < k; i++) { - // Takes the prefix sum up to cows[i] - 1, which calculates the - // number of cows smaller than the current cow - int smaller = segtree.range_sum(0, cows[i]); - - fout << smaller + (k - i - 1) << " \n"[i == k - 1]; - segtree.set(cows[i], 1); - } + if (cows[i] > cows[i - 1]) { + suffix_length++; + } else { + break; + } + } + + int k = n - suffix_length; + fout << k << '\n'; + + SumSegmentTree segtree(n); + for (int i = k; i < n; i++) { segtree.set(cows[i], 1); } + + for (int i = 0; i < k; i++) { + // Takes the prefix sum up to cows[i] - 1, which calculates the + // number of cows smaller than the current cow + int smaller = segtree.range_sum(0, cows[i]); + + fout << smaller + (k - i - 1) << " \n"[i == k - 1]; + segtree.set(cows[i], 1); + } } ``` @@ -192,60 +190,54 @@ public class Sleepy { ```cpp +#include #include #include -#include using std::vector; // BeginCodeSnip{Binary Indexed Tree} struct BIT { - const int n; - vector bit; - BIT(int n) : n(n), bit(n, 0) {} - - void add(int x, int v) { - for (int i = x; i <= n; i += i & -i) { - bit[i] += v; - } - } - - int query(int x) { - int res = 0; - for (int i = x; i > 0; i -= i & -i) { - res += bit[i]; - } - return res; - } + const int n; + vector bit; + BIT(int n) : n(n), bit(n, 0) {} + + void add(int x, int v) { + for (int i = x; i <= n; i += i & -i) { bit[i] += v; } + } + + int query(int x) { + int res = 0; + for (int i = x; i > 0; i -= i & -i) { res += bit[i]; } + return res; + } }; // EndCodeSnip int main() { - std::ifstream fin("sleepy.in"); - std::ofstream fout("sleepy.out"); - - int n; - fin >> n; - vector cows(n + 1); - for (int i = 1; i <= n; i++) { - fin >> cows[i]; - } - - int k = n; - BIT bit(n + 1); - while (cows[k] > cows[k - 1]) { - bit.add(cows[k], 1); - k--; - } - - bit.add(cows[k], 1); - k--; - - fout << k << '\n'; - for (int i = 1; i <= k; i++) { - fout << bit.query(cows[i] - 1) + k - i << " \n"[i == k]; - bit.add(cows[i], 1); - } + std::ifstream fin("sleepy.in"); + std::ofstream fout("sleepy.out"); + + int n; + fin >> n; + vector cows(n + 1); + for (int i = 1; i <= n; i++) { fin >> cows[i]; } + + int k = n; + BIT bit(n + 1); + while (cows[k] > cows[k - 1]) { + bit.add(cows[k], 1); + k--; + } + + bit.add(cows[k], 1); + k--; + + fout << k << '\n'; + for (int i = 1; i <= k; i++) { + fout << bit.query(cows[i] - 1) + k - i << " \n"[i == k]; + bit.add(cows[i], 1); + } } ``` From 03940c090f061f867c3b29d13ede8c9be280f407 Mon Sep 17 00:00:00 2001 From: freakin23 Date: Sun, 9 Feb 2025 08:39:04 +0530 Subject: [PATCH 12/17] update BIT --- solutions/gold/usaco-898.mdx | 44 +++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/solutions/gold/usaco-898.mdx b/solutions/gold/usaco-898.mdx index 1b2ee85715..ff6bf44897 100644 --- a/solutions/gold/usaco-898.mdx +++ b/solutions/gold/usaco-898.mdx @@ -197,20 +197,32 @@ public class Sleepy { using std::vector; // BeginCodeSnip{Binary Indexed Tree} -struct BIT { - const int n; - vector bit; - BIT(int n) : n(n), bit(n, 0) {} - - void add(int x, int v) { - for (int i = x; i <= n; i += i & -i) { bit[i] += v; } - } - - int query(int x) { - int res = 0; - for (int i = x; i > 0; i -= i & -i) { res += bit[i]; } - return res; - } +template class BIT { + private: + int size; + vector bit; + vector arr; + + public: + BIT(int size) : size(size), bit(size + 1), arr(size) {} + + /** Sets the value at index ind to val. */ + void set(int ind, T val) { add(ind, val - arr[ind]); } + + /** Adds val to the element at index ind. */ + void add(int ind, T val) { + arr[ind] += val; + ind++; + for (; ind <= size; ind += ind & -ind) { bit[ind] += val; } + } + + /** @return The sum of all values in [0, ind]. */ + T pref_sum(int ind) { + ind++; + T total = 0; + for (; ind > 0; ind -= ind & -ind) { total += bit[ind]; } + return total; + } }; // EndCodeSnip @@ -224,7 +236,7 @@ int main() { for (int i = 1; i <= n; i++) { fin >> cows[i]; } int k = n; - BIT bit(n + 1); + BIT bit(n + 1); while (cows[k] > cows[k - 1]) { bit.add(cows[k], 1); k--; @@ -235,7 +247,7 @@ int main() { fout << k << '\n'; for (int i = 1; i <= k; i++) { - fout << bit.query(cows[i] - 1) + k - i << " \n"[i == k]; + fout << bit.pref_sum(cows[i] - 1) + k - i << " \n"[i == k]; bit.add(cows[i], 1); } } From 39ad230296b500bbaf525cf703ea1b3b24273ea9 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 9 Feb 2025 03:10:23 +0000 Subject: [PATCH 13/17] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- solutions/gold/usaco-898.mdx | 46 ++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/solutions/gold/usaco-898.mdx b/solutions/gold/usaco-898.mdx index ff6bf44897..f118659617 100644 --- a/solutions/gold/usaco-898.mdx +++ b/solutions/gold/usaco-898.mdx @@ -199,30 +199,30 @@ using std::vector; // BeginCodeSnip{Binary Indexed Tree} template class BIT { private: - int size; - vector bit; - vector arr; - + int size; + vector bit; + vector arr; + public: - BIT(int size) : size(size), bit(size + 1), arr(size) {} - - /** Sets the value at index ind to val. */ - void set(int ind, T val) { add(ind, val - arr[ind]); } - - /** Adds val to the element at index ind. */ - void add(int ind, T val) { - arr[ind] += val; - ind++; - for (; ind <= size; ind += ind & -ind) { bit[ind] += val; } - } - - /** @return The sum of all values in [0, ind]. */ - T pref_sum(int ind) { - ind++; - T total = 0; - for (; ind > 0; ind -= ind & -ind) { total += bit[ind]; } - return total; - } + BIT(int size) : size(size), bit(size + 1), arr(size) {} + + /** Sets the value at index ind to val. */ + void set(int ind, T val) { add(ind, val - arr[ind]); } + + /** Adds val to the element at index ind. */ + void add(int ind, T val) { + arr[ind] += val; + ind++; + for (; ind <= size; ind += ind & -ind) { bit[ind] += val; } + } + + /** @return The sum of all values in [0, ind]. */ + T pref_sum(int ind) { + ind++; + T total = 0; + for (; ind > 0; ind -= ind & -ind) { total += bit[ind]; } + return total; + } }; // EndCodeSnip From c27790533f9442921c8ac4793eaf86ec38c3402e Mon Sep 17 00:00:00 2001 From: freakin23 Date: Sun, 9 Feb 2025 12:55:42 +0530 Subject: [PATCH 14/17] update explanation --- solutions/gold/usaco-898.mdx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/solutions/gold/usaco-898.mdx b/solutions/gold/usaco-898.mdx index f118659617..bc44ae9b1e 100644 --- a/solutions/gold/usaco-898.mdx +++ b/solutions/gold/usaco-898.mdx @@ -18,9 +18,11 @@ Note: The video solution might not be the same as other solutions. Code in C++. ### Using Segment Tree -To obtain the number of cows (**K**) that are not in the correct position, subtract the length of the longest suffix of the array that is already sorted from **N**. Read the analysis of the bronze version of this problem to learn why this is the case. [Analysis](https://usaco.org/current/data/sol_sleepy_bronze_jan19.html) +To obtain the number of cows $K$ that are not in the correct position, subtract the length of the longest suffix of the array that is already sorted from $N$. This makes sense because the problem assumes cows are moved one by one into the sorted part of the line. Once a cow reaches its correct spot in the already-sorted section, it stays there and doesn't cause any more trouble. By focusing on the longest sorted suffix, we're identifying the cows that are already in the right place and don't need to move anymore. This maximizes the number of cows that are "done" and minimizes the number of cows $(K)$ that still need to be rearranged. -Next, for each of these unsorted cows, we calculate how many steps it needs to take to reach its correct position. To do this, we consider two things: first, we count how many cows in the sorted section have a smaller number than the cow we're focusing on. These cows are in the way and need to be bypassed. To make this counting efficient, we use a **Segment Tree** , which lets us quickly find how many smaller cows are ahead without checking each one individually. Second, we count how many cows in the unsorted section are standing to the right of the current cow, as they also block its path. +Next, for each of these unsorted cows, we calculate how many steps it needs to take to reach its correct position. To do this, we consider two things: +1. Count how many cows in the sorted section have a smaller number than the cow we're focusing on. These cows are in the way and need to be bypassed. To make this counting efficient, we use a **Segment Tree** , which lets us quickly find how many smaller cows are ahead without checking each one individually. +2. Count how many cows in the unsorted section are standing to the right of the current cow, as they also block its path. By adding these two numbers together—the cows in the sorted section that are smaller and the cows in the unsorted section ahead of it—we get the total number of steps that cow needs to take to reach its correct spot. This way, we make sure we account for all the obstacles each cow has to pass to get to where it needs to be. From 29c4aec7128c49f077ed541f7484acf95114e6cf Mon Sep 17 00:00:00 2001 From: Kevin Sheng <55369003+SansPapyrus683@users.noreply.github.com> Date: Wed, 12 Feb 2025 09:15:33 -0800 Subject: [PATCH 15/17] Update usaco-898.mdx --- solutions/gold/usaco-898.mdx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/solutions/gold/usaco-898.mdx b/solutions/gold/usaco-898.mdx index bc44ae9b1e..d8f0a7eaa4 100644 --- a/solutions/gold/usaco-898.mdx +++ b/solutions/gold/usaco-898.mdx @@ -68,8 +68,6 @@ template class SumSegmentTree { int main() { std::ifstream fin("sleepy.in"); - std::ofstream fout("sleepy.out"); - int n; fin >> n; vector cows(n); @@ -89,6 +87,7 @@ int main() { } } + std::ofstream fout("sleepy.out"); int k = n - suffix_length; fout << k << '\n'; @@ -186,7 +185,7 @@ public class Sleepy { -### Using Binary Indexed Tree +### Using a BIT @@ -230,8 +229,6 @@ template class BIT { int main() { std::ifstream fin("sleepy.in"); - std::ofstream fout("sleepy.out"); - int n; fin >> n; vector cows(n + 1); @@ -247,6 +244,7 @@ int main() { bit.add(cows[k], 1); k--; + std::ofstream fout("sleepy.out"); fout << k << '\n'; for (int i = 1; i <= k; i++) { fout << bit.pref_sum(cows[i] - 1) + k - i << " \n"[i == k]; From d08d0af9ae91cdab551ae5180d240c432dd9b4bb Mon Sep 17 00:00:00 2001 From: freakin23 Date: Thu, 13 Feb 2025 10:10:20 +0530 Subject: [PATCH 16/17] remove BIT solution --- solutions/gold/usaco-898.mdx | 134 +---------------------------------- 1 file changed, 1 insertion(+), 133 deletions(-) diff --git a/solutions/gold/usaco-898.mdx b/solutions/gold/usaco-898.mdx index bc44ae9b1e..fa21927f56 100644 --- a/solutions/gold/usaco-898.mdx +++ b/solutions/gold/usaco-898.mdx @@ -5,7 +5,7 @@ title: Sleepy Cow Sorting author: Nathan Gong, Melody Yu (Video), Qi Wang, Daniel Ge --- -[Official Analysis](http://www.usaco.org/current/data/sol_sleepy_gold_jan19.html) +[Official Analysis (C++)](http://www.usaco.org/current/data/sol_sleepy_gold_jan19.html) ## Video Solution @@ -186,138 +186,6 @@ public class Sleepy { -### Using Binary Indexed Tree - - - - -```cpp -#include -#include -#include - -using std::vector; - -// BeginCodeSnip{Binary Indexed Tree} -template class BIT { - private: - int size; - vector bit; - vector arr; - - public: - BIT(int size) : size(size), bit(size + 1), arr(size) {} - - /** Sets the value at index ind to val. */ - void set(int ind, T val) { add(ind, val - arr[ind]); } - - /** Adds val to the element at index ind. */ - void add(int ind, T val) { - arr[ind] += val; - ind++; - for (; ind <= size; ind += ind & -ind) { bit[ind] += val; } - } - - /** @return The sum of all values in [0, ind]. */ - T pref_sum(int ind) { - ind++; - T total = 0; - for (; ind > 0; ind -= ind & -ind) { total += bit[ind]; } - return total; - } -}; -// EndCodeSnip - -int main() { - std::ifstream fin("sleepy.in"); - std::ofstream fout("sleepy.out"); - - int n; - fin >> n; - vector cows(n + 1); - for (int i = 1; i <= n; i++) { fin >> cows[i]; } - - int k = n; - BIT bit(n + 1); - while (cows[k] > cows[k - 1]) { - bit.add(cows[k], 1); - k--; - } - - bit.add(cows[k], 1); - k--; - - fout << k << '\n'; - for (int i = 1; i <= k; i++) { - fout << bit.pref_sum(cows[i] - 1) + k - i << " \n"[i == k]; - bit.add(cows[i], 1); - } -} -``` - - - - -```java -import java.io.*; -import java.util.*; - -public class Sleepy { - static int n; - static int[] order, bit, ans; - public static void main(String[] args) throws IOException { - BufferedReader in = new BufferedReader(new FileReader("sleepy.in")); - - n = Integer.parseInt(in.readLine()); - order = new int[n + 1]; - bit = new int[n + 1]; - ans = new int[n + 1]; - - StringTokenizer st = new StringTokenizer(in.readLine()); - for (int i = 1; i <= n; i++) { order[i] = Integer.parseInt(st.nextToken()); } - - int k = n; - while (order[k] > order[k - 1]) { - update(order[k], 1); - k--; - } - - update(order[k], 1); - k--; - - for (int i = 1; i <= k; i++) { - ans[i] = query(order[i] - 1) + k - i; - update(order[i], 1); - } - - PrintWriter out = new PrintWriter("sleepy.out"); - out.println(k); - - for (int i = 1; i < k; i++) { out.print(ans[i] + " "); } - - out.println(ans[k]); - - in.close(); - out.close(); - } - - public static int lowbit(int x) { return x & (-x); } - - public static void update(int x, int k) { - for (int i = x; i <= n; i += lowbit(i)) { bit[i] += k; } - } - - public static int query(int x) { - int ans = 0; - for (int i = x; i > 0; i -= lowbit(i)) { ans += bit[i]; } - return ans; - } -} -``` - - - - ### Using Indexed Set From 49f21db208e35e70c7748e1fa4e39299b1064992 Mon Sep 17 00:00:00 2001 From: freakin23 Date: Thu, 13 Feb 2025 11:54:35 +0530 Subject: [PATCH 17/17] update usaco-898 --- solutions/gold/usaco-898.mdx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/solutions/gold/usaco-898.mdx b/solutions/gold/usaco-898.mdx index 2a7eccbd9d..144fe66b30 100644 --- a/solutions/gold/usaco-898.mdx +++ b/solutions/gold/usaco-898.mdx @@ -10,13 +10,9 @@ author: Nathan Gong, Melody Yu (Video), Qi Wang, Daniel Ge ## Video Solution Note: The video solution might not be the same as other solutions. Code in C++. - + -## Implementation - -**Time Complexity:** $\mathcal{O}(N\log N)$ - -### Using Segment Tree +## Explanation To obtain the number of cows $K$ that are not in the correct position, subtract the length of the longest suffix of the array that is already sorted from $N$. This makes sense because the problem assumes cows are moved one by one into the sorted part of the line. Once a cow reaches its correct spot in the already-sorted section, it stays there and doesn't cause any more trouble. By focusing on the longest sorted suffix, we're identifying the cows that are already in the right place and don't need to move anymore. This maximizes the number of cows that are "done" and minimizes the number of cows $(K)$ that still need to be rearranged. @@ -26,6 +22,10 @@ Next, for each of these unsorted cows, we calculate how many steps it needs to t By adding these two numbers together—the cows in the sorted section that are smaller and the cows in the unsorted section ahead of it—we get the total number of steps that cow needs to take to reach its correct spot. This way, we make sure we account for all the obstacles each cow has to pass to get to where it needs to be. +## Implementation + +**Time Complexity:** $\mathcal{O}(N\log N)$ + @@ -185,7 +185,7 @@ public class Sleepy { -### Using Indexed Set +## Alternate Solution (Using Indexed Set)