From 9cf637f0f21454265ee4e019b681f49dfb7713ee Mon Sep 17 00:00:00 2001 From: Justin Ji Date: Fri, 27 Sep 2024 21:46:38 -0700 Subject: [PATCH 01/10] Fenwick Tree Updates --- content/5_Plat/2DRQ.mdx | 398 ++++++++++++++++++++++------------------ 1 file changed, 218 insertions(+), 180 deletions(-) diff --git a/content/5_Plat/2DRQ.mdx b/content/5_Plat/2DRQ.mdx index e6eb86f269..cf8c8854c4 100644 --- a/content/5_Plat/2DRQ.mdx +++ b/content/5_Plat/2DRQ.mdx @@ -2,7 +2,7 @@ id: 2DRQ title: '2D Range Queries' author: Benjamin Qi, Andi Qu -contributors: Daniel Zhu +contributors: Daniel Zhu, Justin Ji prerequisites: - sparse-segtree description: 'Extending Range Queries to 2D (and beyond).' @@ -52,59 +52,77 @@ query subrectangles. ```cpp #include using namespace std; - -int bit[1001][1001]; -int n; - -void update(int x, int y, int val) { - for (; x <= n; x += (x & (-x))) { - for (int i = y; i <= n; i += (i & (-i))) { bit[x][i] += val; } - } -} - -int query(int x1, int y1, int x2, int y2) { - int ans = 0; - for (int i = x2; i; i -= (i & (-i))) { - for (int j = y2; j; j -= (j & (-j))) { ans += bit[i][j]; } - } - for (int i = x2; i; i -= (i & (-i))) { - for (int j = y1 - 1; j; j -= (j & (-j))) { ans -= bit[i][j]; } - } - for (int i = x1 - 1; i; i -= (i & (-i))) { - for (int j = y2; j; j -= (j & (-j))) { ans -= bit[i][j]; } - } - for (int i = x1 - 1; i; i -= (i & (-i))) { - for (int j = y1 - 1; j; j -= (j & (-j))) { ans += bit[i][j]; } - } - return ans; -} + +/** + * 2D Fenwick Tree implementation. + * Note that all cell locations are zero-indexed + * in this implementation. + */ +template class BIT2D { + private: + const int n, m; + vector> bit; + + public: + BIT2D(int n, int m) : n(n), m(m), bit(n + 1, vector(m + 1)) {} + + void add(int r, int c, T val) { + r++, c++; + for (; r <= n; r += r & -r) { + for (int i = c; i <= m; i += i & -i) { + bit[r][i] += val; + } + } + } + + T rect_sum(int r, int c) { + r++, c++; + T sum = 0; + for (; r > 0; r -= r & -r) { + for (int i = c; i > 0; i -= i & -i) { + sum += bit[r][i]; + } + } + return sum; + } + + T rect_sum(int r1, int c1, int r2, int c2) { + return rect_sum(r2, c2) - rect_sum(r2, c1 - 1) - + rect_sum(r1 - 1, c2) + rect_sum(r1 - 1, c1 - 1); + } +}; int main() { - iostream::sync_with_stdio(false); - cin.tie(0); - int q; - cin >> n >> q; - for (int i = 1; i <= n; i++) - for (int j = 1; j <= n; j++) { - char c; - cin >> c; - if (c == '*') update(j, i, 1); - } - while (q--) { - int t; - cin >> t; - if (t == 1) { - int x, y; - cin >> y >> x; - if (query(x, y, x, y)) update(x, y, -1); - else update(x, y, 1); - } else { - int y1, x1, y2, x2; - cin >> y1 >> x1 >> y2 >> x2; - cout << query(x1, y1, x2, y2) << '\n'; - } - } - return 0; + int n, q; + cin >> n >> q; + BIT2D bit(n, n); + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + char c; + cin >> c; + if (c == '*') { bit.add(i, j, 1); } + } + } + + for (int i = 0; i < q; i++) { + int type; + cin >> type; + if (type == 1) { + int r, c; + cin >> r >> c; + r--, c--; + if (bit.rect_sum(r, c, r, c) == 1) { + bit.add(r, c, -1); + } else { + bit.add(r, c, 1); + } + } else { + int r1, c1, r2, c2; + cin >> r1 >> c1 >> r2 >> c2; + r1--, c1--, r2--, c2--; + cout << bit.rect_sum(r1, c1, r2, c2) << "\n"; + } + } } ``` @@ -259,59 +277,74 @@ easier to understand, albeit significantly slower due to a high constant factor: ```cpp -// index of largest value <= x in v (sorted) -// if v = [1, 2, 4], ind(v, 3) would return 1 -int ind(vector v, int x) { - return upper_bound(v.begin(), v.end(), x) - v.begin() - 1; -} +#include +using namespace std; +using ll = long long; -class BIT2D { +/** + * Offline 2D Fenwick Tree implementation. + * Note that n needs to be of a reasonable size, and + * all the updates/queries inputs are zero indexed. + */ +template class OfflineBIT2D { private: - int n; // max x-coordinate - vector> vals, bit; + const int n; + vector> vals; + vector> bit; - public: - BIT2D(int n, vector> &todo) : n(n), vals(n + 1), bit(n + 1) { - // sort points by y-coordinate - sort(todo.begin(), todo.end(), - [](pair a, pair b) { return a.second < b.second; }); - // ensures vals and bit are 1-indexed - for (int i = 1; i <= n; i++) { vals[i].push_back(0); } - for (auto [x, y] : todo) { - for (int z = x; z <= n; z += z & -z) { - if (vals[z].back() != y) { vals[z].push_back(y); } - } - } - for (int i = 1; i <= n; i++) { bit[i].resize(vals[i].size()); } - } + int ind(const vector &v, int x) { + return upper_bound(begin(v), end(v), x) - begin(v) - 1; + } - /** adds t to the point (x, y) */ - void upd(int x, int y, int t = 1) { - for (; x <= n; x += x & -x) { - int z = ind(vals[x], y); - assert(z && vals[x][z] == y); - for (; z < bit[x].size(); z += z & -z) { bit[x][z] += t; } - } - } - - /** @return sum of points in rectangle with top-right corner (x, y) */ - int query(int x, int y) { - int tot = 0; - for (; x > 0; x -= x & -x) { - for (int z = ind(vals[x], y); z > 0; z -= z & -z) { tot += bit[x][z]; } - } - return tot; - } - - /** @returns sum of points with x in [x1, x2] and y in [y1, y2] */ - int query(int x1, int x2, int y1, int y2) { - if (x1 > x2 || y1 > y2) { return 0; } - int tr = query(x2, y2); // top-right - int tl = query(x1 - 1, y2); // top-left - int br = query(x2, y1 - 1); // bottom-right - int bl = query(x1 - 1, y1 - 1); // bottom-left - return tr - tl - br + bl; - } + public: + OfflineBIT2D(int _n, vector> &todo) + : n(_n), vals(n + 1), bit(n + 1) { + sort(begin(todo), end(todo), + [](const array &a, const array &b) -> bool { + return a[1] < b[1]; + }); + + for (int i = 1; i <= n; i++) { vals[i].push_back(0); } + for (auto [r, c] : todo) { + r++, c++; + for (; r <= n; r += r & -r) { + if (vals[r].back() != c) { vals[r].push_back(c); } + } + } + for (int i = 1; i <= n; i++) { + bit[i].resize(vals[i].size()); + } + } + + /** adds val to the point (r, c) */ + void add(int r, int c, T val) { + r++, c++; + for (; r <= n; r += r & -r) { + int i = ind(vals[r], c); + for (; i < bit[r].size(); i += i & -i) { + bit[r][i] += val; + } + } + } + + /** @return rectangle sum for corners (0, 0), (r, c) */ + T rect_sum(int r, int c) { + r++, c++; + T sum = 0; + for (; r > 0; r -= r & -r) { + int i = ind(vals[r], c); + for (; i > 0; i -= i & -i) { + sum += bit[r][i]; + } + } + return sum; + } + + /** @return rectangle sum with corners (r1, c1) and (r2, c2) */ + T rect_sum(int r1, int c1, int r2, int c2) { + return rect_sum(r2, c2) - rect_sum(r2, c1 - 1) - + rect_sum(r1 - 1, c2) + rect_sum(r1 - 1, c1 - 1); + } }; ``` @@ -322,94 +355,99 @@ And you might use it like so: + ```cpp -#include -#include -#include -#include +#include using namespace std; using ll = long long; -// BeginCodeSnip{BIT2D} -// index of largest value <= x in v (sorted) -// if v = [1, 2, 4], ind(v, 3) would return 1 -int ind(vector v, int x) { - return upper_bound(v.begin(), v.end(), x) - v.begin() - 1; -} - -class BIT2D { +/** + * Offline 2D Fenwick Tree implementation. + * Note that n needs to be of a reasonable size, and + * all the updates/queries inputs are zero indexed. + */ +template class OfflineBIT2D { private: - int n; // max x-coordinate - vector> vals, bit; - - public: - BIT2D(int n, vector> &todo) : n(n), vals(n + 1), bit(n + 1) { - // sort points by y-coordinate - sort(todo.begin(), todo.end(), - [](pair a, pair b) { return a.second < b.second; }); - // ensures vals and bit are 1-indexed - for (int i = 1; i <= n; i++) { vals[i].push_back(0); } - for (auto [x, y] : todo) { - for (int z = x; z <= n; z += z & -z) { - if (vals[z].back() != y) { vals[z].push_back(y); } - } - } - for (int i = 1; i <= n; i++) { bit[i].resize(vals[i].size()); } - } + const int n; + vector> vals; + vector> bit; - /** adds t to the point (x, y) */ - void upd(int x, int y, int t = 1) { - for (; x <= n; x += x & -x) { - int z = ind(vals[x], y); - assert(z && vals[x][z] == y); - for (; z < bit[x].size(); z += z & -z) { bit[x][z] += t; } - } - } + int ind(const vector &v, int x) { + return upper_bound(begin(v), end(v), x) - begin(v) - 1; + } - /** @return sum of points in rectangle with top-right corner (x, y) */ - int query(int x, int y) { - int tot = 0; - for (; x > 0; x -= x & -x) { - for (int z = ind(vals[x], y); z > 0; z -= z & -z) { tot += bit[x][z]; } - } - return tot; - } - - /** @returns sum of points with x in [x1, x2] and y in [y1, y2] */ - int query(int x1, int x2, int y1, int y2) { - if (x1 > x2 || y1 > y2) { return 0; } - int tr = query(x2, y2); // top-right - int tl = query(x1 - 1, y2); // top-left - int br = query(x2, y1 - 1); // bottom-right - int bl = query(x1 - 1, y1 - 1); // bottom-left - return tr - tl - br + bl; - } + public: + OfflineBIT2D(int _n, vector> &todo) + : n(_n), vals(n + 1), bit(n + 1) { + sort(begin(todo), end(todo), + [](const array &a, const array &b) -> bool { + return a[1] < b[1]; + }); + + for (int i = 1; i <= n; i++) { vals[i].push_back(0); } + for (auto [r, c] : todo) { + r++, c++; + for (; r <= n; r += r & -r) { + if (vals[r].back() != c) { vals[r].push_back(c); } + } + } + for (int i = 1; i <= n; i++) { + bit[i].resize(vals[i].size()); + } + } + + /** adds val to the point (r, c) */ + void add(int r, int c, T val) { + r++, c++; + for (; r <= n; r += r & -r) { + int i = ind(vals[r], c); + for (; i < bit[r].size(); i += i & -i) { + bit[r][i] += val; + } + } + } + + /** @return rectangle sum for corners (0, 0), (r, c) */ + T rect_sum(int r, int c) { + r++, c++; + T sum = 0; + for (; r > 0; r -= r & -r) { + int i = ind(vals[r], c); + for (; i > 0; i -= i & -i) { + sum += bit[r][i]; + } + } + return sum; + } + + /** @return rectangle sum with corners (r1, c1) and (r2, c2) */ + T rect_sum(int r1, int c1, int r2, int c2) { + return rect_sum(r2, c2) - rect_sum(r2, c1 - 1) - + rect_sum(r1 - 1, c2) + rect_sum(r1 - 1, c1 - 1); + } }; -// EndCodeSnip int main() { - int n; - cin >> n; - vector a(n + 1), p(n + 1); - vector> updates; - for (int i = 1; i <= n; i++) { - cin >> a[i]; - // register all updates offline - updates.push_back({i, a[i]}); - } - - // intialize BIT from list of updates - BIT2D bit(n, updates); - for (int i = 1; i <= n; i++) { cin >> p[i]; } - - ll ans = 0; - // now we can update and query like normal - for (int i = 1; i <= n; i++) { - ans += bit.query(1, p[i], a[p[i]] + 1, n); - ans += bit.query(p[i], n, 1, a[p[i]] - 1); - cout << ans << "\n"; - bit.upd(p[i], a[p[i]]); - } + int n; + cin >> n; + vector a(n), p(n); + for (int &i : a) { cin >> i; } + for (int &i : p) { cin >> i, i--; } + + vector> upd(n); + for (int i = 0; i < n; i++) { + upd[i] = {p[i], a[p[i]]}; + } + OfflineBIT2D bit(n, upd); + + ll res = 0; + const int mx = *max_element(begin(a), end(a)); + for (int i = 0; i < n; i++) { + res += bit.rect_sum(0, a[p[i]] + 1, p[i] - 1, mx); + res += bit.rect_sum(p[i] + 1, 0, n - 1, a[p[i]] - 1); + cout << res << "\n"; + bit.add(p[i], a[p[i]], 1); + } } ``` @@ -418,7 +456,7 @@ int main() { -As mentioned earlier, the above `BIT2D` implementation is significantly slower than Benq's `OffBIT2D` and, in fact, will get TLE on the Soriya's Programming Project; this is due to the large amount of calls to `vector.resize` it makes. +As mentioned earlier, the above `OfflineBIT2D` implementation is significantly slower than Benq's `OffBIT2D` and, in fact, will get TLE on the Soriya's Programming Project. From c47626d2cac2c34d9df4a01602802be5ec0a5efe Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 28 Sep 2024 04:51:04 +0000 Subject: [PATCH 02/10] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- content/5_Plat/2DRQ.mdx | 354 +++++++++++++++++++--------------------- 1 file changed, 167 insertions(+), 187 deletions(-) diff --git a/content/5_Plat/2DRQ.mdx b/content/5_Plat/2DRQ.mdx index cf8c8854c4..3eac8c4f16 100644 --- a/content/5_Plat/2DRQ.mdx +++ b/content/5_Plat/2DRQ.mdx @@ -52,7 +52,7 @@ query subrectangles. ```cpp #include using namespace std; - + /** * 2D Fenwick Tree implementation. * Note that all cell locations are zero-indexed @@ -60,69 +60,65 @@ using namespace std; */ template class BIT2D { private: - const int n, m; - vector> bit; - + const int n, m; + vector> bit; + public: - BIT2D(int n, int m) : n(n), m(m), bit(n + 1, vector(m + 1)) {} - - void add(int r, int c, T val) { - r++, c++; - for (; r <= n; r += r & -r) { - for (int i = c; i <= m; i += i & -i) { - bit[r][i] += val; - } - } - } - - T rect_sum(int r, int c) { - r++, c++; - T sum = 0; - for (; r > 0; r -= r & -r) { - for (int i = c; i > 0; i -= i & -i) { - sum += bit[r][i]; - } - } - return sum; - } - - T rect_sum(int r1, int c1, int r2, int c2) { - return rect_sum(r2, c2) - rect_sum(r2, c1 - 1) - - rect_sum(r1 - 1, c2) + rect_sum(r1 - 1, c1 - 1); - } + BIT2D(int n, int m) : n(n), m(m), bit(n + 1, vector(m + 1)) {} + + void add(int r, int c, T val) { + r++, c++; + for (; r <= n; r += r & -r) { + for (int i = c; i <= m; i += i & -i) { bit[r][i] += val; } + } + } + + T rect_sum(int r, int c) { + r++, c++; + T sum = 0; + for (; r > 0; r -= r & -r) { + for (int i = c; i > 0; i -= i & -i) { sum += bit[r][i]; } + } + return sum; + } + + T rect_sum(int r1, int c1, int r2, int c2) { + return rect_sum(r2, c2) - rect_sum(r2, c1 - 1) - rect_sum(r1 - 1, c2) + + rect_sum(r1 - 1, c1 - 1); + } }; int main() { - int n, q; - cin >> n >> q; - BIT2D bit(n, n); - for (int i = 0; i < n; i++) { - for (int j = 0; j < n; j++) { - char c; - cin >> c; - if (c == '*') { bit.add(i, j, 1); } - } - } - - for (int i = 0; i < q; i++) { - int type; - cin >> type; - if (type == 1) { - int r, c; - cin >> r >> c; - r--, c--; - if (bit.rect_sum(r, c, r, c) == 1) { - bit.add(r, c, -1); - } else { - bit.add(r, c, 1); - } - } else { - int r1, c1, r2, c2; - cin >> r1 >> c1 >> r2 >> c2; - r1--, c1--, r2--, c2--; - cout << bit.rect_sum(r1, c1, r2, c2) << "\n"; - } - } + int n, q; + cin >> n >> q; + BIT2D bit(n, n); + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + char c; + cin >> c; + if (c == '*') { bit.add(i, j, 1); } + } + } + + for (int i = 0; i < q; i++) { + int type; + cin >> type; + if (type == 1) { + int r, c; + cin >> r >> c; + r--, c--; + if (bit.rect_sum(r, c, r, c) == 1) { + bit.add(r, c, -1); + } else { + bit.add(r, c, 1); + } + } else { + int r1, c1, r2, c2; + cin >> r1 >> c1 >> r2 >> c2; + r1--, c1--, r2--, c2--; + cout << bit.rect_sum(r1, c1, r2, c2) << "\n"; + } + } } ``` @@ -288,63 +284,56 @@ using ll = long long; */ template class OfflineBIT2D { private: - const int n; - vector> vals; - vector> bit; + const int n; + vector> vals; + vector> bit; - int ind(const vector &v, int x) { - return upper_bound(begin(v), end(v), x) - begin(v) - 1; - } + int ind(const vector &v, int x) { + return upper_bound(begin(v), end(v), x) - begin(v) - 1; + } public: - OfflineBIT2D(int _n, vector> &todo) - : n(_n), vals(n + 1), bit(n + 1) { - sort(begin(todo), end(todo), - [](const array &a, const array &b) -> bool { - return a[1] < b[1]; - }); - - for (int i = 1; i <= n; i++) { vals[i].push_back(0); } - for (auto [r, c] : todo) { - r++, c++; - for (; r <= n; r += r & -r) { - if (vals[r].back() != c) { vals[r].push_back(c); } - } - } - for (int i = 1; i <= n; i++) { - bit[i].resize(vals[i].size()); - } - } - - /** adds val to the point (r, c) */ - void add(int r, int c, T val) { - r++, c++; - for (; r <= n; r += r & -r) { - int i = ind(vals[r], c); - for (; i < bit[r].size(); i += i & -i) { - bit[r][i] += val; - } - } - } - - /** @return rectangle sum for corners (0, 0), (r, c) */ - T rect_sum(int r, int c) { - r++, c++; - T sum = 0; - for (; r > 0; r -= r & -r) { - int i = ind(vals[r], c); - for (; i > 0; i -= i & -i) { - sum += bit[r][i]; - } - } - return sum; - } - - /** @return rectangle sum with corners (r1, c1) and (r2, c2) */ - T rect_sum(int r1, int c1, int r2, int c2) { - return rect_sum(r2, c2) - rect_sum(r2, c1 - 1) - - rect_sum(r1 - 1, c2) + rect_sum(r1 - 1, c1 - 1); - } + OfflineBIT2D(int _n, vector> &todo) : n(_n), vals(n + 1), bit(n + 1) { + sort(begin(todo), end(todo), + [](const array &a, const array &b) -> bool { + return a[1] < b[1]; + }); + + for (int i = 1; i <= n; i++) { vals[i].push_back(0); } + for (auto [r, c] : todo) { + r++, c++; + for (; r <= n; r += r & -r) { + if (vals[r].back() != c) { vals[r].push_back(c); } + } + } + for (int i = 1; i <= n; i++) { bit[i].resize(vals[i].size()); } + } + + /** adds val to the point (r, c) */ + void add(int r, int c, T val) { + r++, c++; + for (; r <= n; r += r & -r) { + int i = ind(vals[r], c); + for (; i < bit[r].size(); i += i & -i) { bit[r][i] += val; } + } + } + + /** @return rectangle sum for corners (0, 0), (r, c) */ + T rect_sum(int r, int c) { + r++, c++; + T sum = 0; + for (; r > 0; r -= r & -r) { + int i = ind(vals[r], c); + for (; i > 0; i -= i & -i) { sum += bit[r][i]; } + } + return sum; + } + + /** @return rectangle sum with corners (r1, c1) and (r2, c2) */ + T rect_sum(int r1, int c1, int r2, int c2) { + return rect_sum(r2, c2) - rect_sum(r2, c1 - 1) - rect_sum(r1 - 1, c2) + + rect_sum(r1 - 1, c1 - 1); + } }; ``` @@ -368,86 +357,77 @@ using ll = long long; */ template class OfflineBIT2D { private: - const int n; - vector> vals; - vector> bit; + const int n; + vector> vals; + vector> bit; - int ind(const vector &v, int x) { - return upper_bound(begin(v), end(v), x) - begin(v) - 1; - } + int ind(const vector &v, int x) { + return upper_bound(begin(v), end(v), x) - begin(v) - 1; + } public: - OfflineBIT2D(int _n, vector> &todo) - : n(_n), vals(n + 1), bit(n + 1) { - sort(begin(todo), end(todo), - [](const array &a, const array &b) -> bool { - return a[1] < b[1]; - }); - - for (int i = 1; i <= n; i++) { vals[i].push_back(0); } - for (auto [r, c] : todo) { - r++, c++; - for (; r <= n; r += r & -r) { - if (vals[r].back() != c) { vals[r].push_back(c); } - } - } - for (int i = 1; i <= n; i++) { - bit[i].resize(vals[i].size()); - } - } - - /** adds val to the point (r, c) */ - void add(int r, int c, T val) { - r++, c++; - for (; r <= n; r += r & -r) { - int i = ind(vals[r], c); - for (; i < bit[r].size(); i += i & -i) { - bit[r][i] += val; - } - } - } - - /** @return rectangle sum for corners (0, 0), (r, c) */ - T rect_sum(int r, int c) { - r++, c++; - T sum = 0; - for (; r > 0; r -= r & -r) { - int i = ind(vals[r], c); - for (; i > 0; i -= i & -i) { - sum += bit[r][i]; - } - } - return sum; - } - - /** @return rectangle sum with corners (r1, c1) and (r2, c2) */ - T rect_sum(int r1, int c1, int r2, int c2) { - return rect_sum(r2, c2) - rect_sum(r2, c1 - 1) - - rect_sum(r1 - 1, c2) + rect_sum(r1 - 1, c1 - 1); - } + OfflineBIT2D(int _n, vector> &todo) : n(_n), vals(n + 1), bit(n + 1) { + sort(begin(todo), end(todo), + [](const array &a, const array &b) -> bool { + return a[1] < b[1]; + }); + + for (int i = 1; i <= n; i++) { vals[i].push_back(0); } + for (auto [r, c] : todo) { + r++, c++; + for (; r <= n; r += r & -r) { + if (vals[r].back() != c) { vals[r].push_back(c); } + } + } + for (int i = 1; i <= n; i++) { bit[i].resize(vals[i].size()); } + } + + /** adds val to the point (r, c) */ + void add(int r, int c, T val) { + r++, c++; + for (; r <= n; r += r & -r) { + int i = ind(vals[r], c); + for (; i < bit[r].size(); i += i & -i) { bit[r][i] += val; } + } + } + + /** @return rectangle sum for corners (0, 0), (r, c) */ + T rect_sum(int r, int c) { + r++, c++; + T sum = 0; + for (; r > 0; r -= r & -r) { + int i = ind(vals[r], c); + for (; i > 0; i -= i & -i) { sum += bit[r][i]; } + } + return sum; + } + + /** @return rectangle sum with corners (r1, c1) and (r2, c2) */ + T rect_sum(int r1, int c1, int r2, int c2) { + return rect_sum(r2, c2) - rect_sum(r2, c1 - 1) - rect_sum(r1 - 1, c2) + + rect_sum(r1 - 1, c1 - 1); + } }; int main() { - int n; - cin >> n; - vector a(n), p(n); - for (int &i : a) { cin >> i; } - for (int &i : p) { cin >> i, i--; } - - vector> upd(n); - for (int i = 0; i < n; i++) { - upd[i] = {p[i], a[p[i]]}; - } - OfflineBIT2D bit(n, upd); - - ll res = 0; + int n; + cin >> n; + vector a(n), p(n); + for (int &i : a) { cin >> i; } + for (int &i : p) { cin >> i, i--; } + + vector> upd(n); + for (int i = 0; i < n; i++) { upd[i] = {p[i], a[p[i]]}; } + OfflineBIT2D bit(n, upd); + + ll res = 0; const int mx = *max_element(begin(a), end(a)); - for (int i = 0; i < n; i++) { - res += bit.rect_sum(0, a[p[i]] + 1, p[i] - 1, mx); - res += bit.rect_sum(p[i] + 1, 0, n - 1, a[p[i]] - 1); - cout << res << "\n"; - bit.add(p[i], a[p[i]], 1); - } + for (int i = 0; i < n; i++) { + res += bit.rect_sum(0, a[p[i]] + 1, p[i] - 1, mx); + res += bit.rect_sum(p[i] + 1, 0, n - 1, a[p[i]] - 1); + cout << res << "\n"; + bit.add(p[i], a[p[i]], 1); + } } ``` From 4bb704b0cdf3e7c186e2760c04aaa72859cd6ba9 Mon Sep 17 00:00:00 2001 From: Justin Ji <68484800+TheGamingMousse@users.noreply.github.com> Date: Sat, 28 Sep 2024 11:05:22 -0700 Subject: [PATCH 03/10] Update content/5_Plat/2DRQ.mdx Co-authored-by: Kevin Sheng <55369003+SansPapyrus683@users.noreply.github.com> --- content/5_Plat/2DRQ.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/5_Plat/2DRQ.mdx b/content/5_Plat/2DRQ.mdx index 3eac8c4f16..2d2c6a0f0c 100644 --- a/content/5_Plat/2DRQ.mdx +++ b/content/5_Plat/2DRQ.mdx @@ -116,7 +116,7 @@ int main() { int r1, c1, r2, c2; cin >> r1 >> c1 >> r2 >> c2; r1--, c1--, r2--, c2--; - cout << bit.rect_sum(r1, c1, r2, c2) << "\n"; + cout << bit.rect_sum(r1, c1, r2, c2) << '\n'; } } } From 8f6a2705fdff7d0822195e79d8cf30f81570c3bc Mon Sep 17 00:00:00 2001 From: Justin Ji <68484800+TheGamingMousse@users.noreply.github.com> Date: Sat, 28 Sep 2024 11:05:28 -0700 Subject: [PATCH 04/10] Update content/5_Plat/2DRQ.mdx Co-authored-by: Kevin Sheng <55369003+SansPapyrus683@users.noreply.github.com> --- content/5_Plat/2DRQ.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/5_Plat/2DRQ.mdx b/content/5_Plat/2DRQ.mdx index 2d2c6a0f0c..ff66381446 100644 --- a/content/5_Plat/2DRQ.mdx +++ b/content/5_Plat/2DRQ.mdx @@ -112,7 +112,7 @@ int main() { } else { bit.add(r, c, 1); } - } else { + } else if (type == 2) { int r1, c1, r2, c2; cin >> r1 >> c1 >> r2 >> c2; r1--, c1--, r2--, c2--; From c72347f7892dc6b6e2ecaddcd03ab6692d6860bd Mon Sep 17 00:00:00 2001 From: TheGamingMousse <68484800+TheGamingMousse@users.noreply.github.com> Date: Sat, 28 Sep 2024 11:19:49 -0700 Subject: [PATCH 05/10] Update 2DRQ.mdx --- content/5_Plat/2DRQ.mdx | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/content/5_Plat/2DRQ.mdx b/content/5_Plat/2DRQ.mdx index ff66381446..47f59e1254 100644 --- a/content/5_Plat/2DRQ.mdx +++ b/content/5_Plat/2DRQ.mdx @@ -66,6 +66,7 @@ template class BIT2D { public: BIT2D(int n, int m) : n(n), m(m), bit(n + 1, vector(m + 1)) {} + /** adds val to the point (r, c) */ void add(int r, int c, T val) { r++, c++; for (; r <= n; r += r & -r) { @@ -73,6 +74,7 @@ template class BIT2D { } } + /** @returns sum of points with row in [0, r] and column in [0, c] */ T rect_sum(int r, int c) { r++, c++; T sum = 0; @@ -82,6 +84,7 @@ template class BIT2D { return sum; } + /** @returns sum of points with row in [r1, r2] and column in [c1, c2] */ T rect_sum(int r1, int c1, int r2, int c2) { return rect_sum(r2, c2) - rect_sum(r2, c1 - 1) - rect_sum(r1 - 1, c2) + rect_sum(r1 - 1, c1 - 1); @@ -288,12 +291,13 @@ template class OfflineBIT2D { vector> vals; vector> bit; + /** @return the first index i such that v[i] <= x */ int ind(const vector &v, int x) { return upper_bound(begin(v), end(v), x) - begin(v) - 1; } public: - OfflineBIT2D(int _n, vector> &todo) : n(_n), vals(n + 1), bit(n + 1) { + OfflineBIT2D(int n, vector> &todo) : n(n), vals(n + 1), bit(n + 1) { sort(begin(todo), end(todo), [](const array &a, const array &b) -> bool { return a[1] < b[1]; @@ -318,7 +322,7 @@ template class OfflineBIT2D { } } - /** @return rectangle sum for corners (0, 0), (r, c) */ + /** @returns sum of points with row in [0, r] and column in [0, c] */ T rect_sum(int r, int c) { r++, c++; T sum = 0; @@ -329,7 +333,7 @@ template class OfflineBIT2D { return sum; } - /** @return rectangle sum with corners (r1, c1) and (r2, c2) */ + /** @returns sum of points with row in [r1, r2] and column in [c1, c2] */ T rect_sum(int r1, int c1, int r2, int c2) { return rect_sum(r2, c2) - rect_sum(r2, c1 - 1) - rect_sum(r1 - 1, c2) + rect_sum(r1 - 1, c1 - 1); @@ -350,23 +354,20 @@ And you might use it like so: using namespace std; using ll = long long; -/** - * Offline 2D Fenwick Tree implementation. - * Note that n needs to be of a reasonable size, and - * all the updates/queries inputs are zero indexed. - */ +// BeginCodeSnip{Offline 2D BIT (from the module)} template class OfflineBIT2D { private: const int n; vector> vals; vector> bit; + /** @return the first index i such that v[i] <= x */ int ind(const vector &v, int x) { return upper_bound(begin(v), end(v), x) - begin(v) - 1; } public: - OfflineBIT2D(int _n, vector> &todo) : n(_n), vals(n + 1), bit(n + 1) { + OfflineBIT2D(int n, vector> &todo) : n(n), vals(n + 1), bit(n + 1) { sort(begin(todo), end(todo), [](const array &a, const array &b) -> bool { return a[1] < b[1]; @@ -391,7 +392,7 @@ template class OfflineBIT2D { } } - /** @return rectangle sum for corners (0, 0), (r, c) */ + /** @returns sum of points with row in [0, r] and column in [0, c] */ T rect_sum(int r, int c) { r++, c++; T sum = 0; @@ -402,12 +403,13 @@ template class OfflineBIT2D { return sum; } - /** @return rectangle sum with corners (r1, c1) and (r2, c2) */ + /** @returns sum of points with r in [r1, r2] and c in [c1, c2] */ T rect_sum(int r1, int c1, int r2, int c2) { return rect_sum(r2, c2) - rect_sum(r2, c1 - 1) - rect_sum(r1 - 1, c2) + rect_sum(r1 - 1, c1 - 1); } }; +// EndCodeSnip int main() { int n; @@ -576,4 +578,4 @@ Possible ways to get around this: Can also try the USACO problems from above. - + \ No newline at end of file From 7b7ff51bc6fe3487aecb3095cd4f7649c9daf67d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 28 Sep 2024 18:21:04 +0000 Subject: [PATCH 06/10] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- content/5_Plat/2DRQ.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/5_Plat/2DRQ.mdx b/content/5_Plat/2DRQ.mdx index 47f59e1254..3fbabb941f 100644 --- a/content/5_Plat/2DRQ.mdx +++ b/content/5_Plat/2DRQ.mdx @@ -578,4 +578,4 @@ Possible ways to get around this: Can also try the USACO problems from above. - \ No newline at end of file + From f442daa01e1db9b8be0da5cd7a0c6e560d64e136 Mon Sep 17 00:00:00 2001 From: Justin Ji <68484800+TheGamingMousse@users.noreply.github.com> Date: Sat, 28 Sep 2024 11:28:39 -0700 Subject: [PATCH 07/10] Update content/5_Plat/2DRQ.mdx Co-authored-by: Kevin Sheng <55369003+SansPapyrus683@users.noreply.github.com> --- content/5_Plat/2DRQ.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/5_Plat/2DRQ.mdx b/content/5_Plat/2DRQ.mdx index 3fbabb941f..d7a9cfb457 100644 --- a/content/5_Plat/2DRQ.mdx +++ b/content/5_Plat/2DRQ.mdx @@ -354,7 +354,7 @@ And you might use it like so: using namespace std; using ll = long long; -// BeginCodeSnip{Offline 2D BIT (from the module)} +// BeginCodeSnip{Offline 2D BIT} template class OfflineBIT2D { private: const int n; From 5bfbbe508c579b07f2a929282356fe34d5eb5e1a Mon Sep 17 00:00:00 2001 From: Justin Ji <68484800+TheGamingMousse@users.noreply.github.com> Date: Sat, 28 Sep 2024 11:29:01 -0700 Subject: [PATCH 08/10] Update content/5_Plat/2DRQ.mdx Co-authored-by: Kevin Sheng <55369003+SansPapyrus683@users.noreply.github.com> --- content/5_Plat/2DRQ.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/5_Plat/2DRQ.mdx b/content/5_Plat/2DRQ.mdx index d7a9cfb457..455526ed86 100644 --- a/content/5_Plat/2DRQ.mdx +++ b/content/5_Plat/2DRQ.mdx @@ -427,7 +427,7 @@ int main() { for (int i = 0; i < n; i++) { res += bit.rect_sum(0, a[p[i]] + 1, p[i] - 1, mx); res += bit.rect_sum(p[i] + 1, 0, n - 1, a[p[i]] - 1); - cout << res << "\n"; + cout << res << '\n'; bit.add(p[i], a[p[i]], 1); } } From 145c3548aed76516a99038173bd463a55ccd3460 Mon Sep 17 00:00:00 2001 From: TheGamingMousse <68484800+TheGamingMousse@users.noreply.github.com> Date: Sat, 28 Sep 2024 11:36:05 -0700 Subject: [PATCH 09/10] style changes --- content/5_Plat/2DRQ.mdx | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/content/5_Plat/2DRQ.mdx b/content/5_Plat/2DRQ.mdx index 47f59e1254..0fb4c2a83e 100644 --- a/content/5_Plat/2DRQ.mdx +++ b/content/5_Plat/2DRQ.mdx @@ -50,7 +50,8 @@ query subrectangles. ```cpp -#include +#include +#include using namespace std; /** @@ -276,14 +277,17 @@ easier to understand, albeit significantly slower due to a high constant factor: ```cpp -#include +#include +#include +#include +#include using namespace std; -using ll = long long; /** * Offline 2D Fenwick Tree implementation. - * Note that n needs to be of a reasonable size, and - * all the updates/queries inputs are zero indexed. + * Note that all the update and query indices + * are zero-indexed, and that the rows are not + * coordinate compressed in this implementation. */ template class OfflineBIT2D { private: @@ -350,18 +354,20 @@ And you might use it like so: ```cpp -#include +#include +#include +#include +#include using namespace std; using ll = long long; -// BeginCodeSnip{Offline 2D BIT (from the module)} +// BeginCodeSnip{Offline 2D BIT} template class OfflineBIT2D { private: const int n; vector> vals; vector> bit; - /** @return the first index i such that v[i] <= x */ int ind(const vector &v, int x) { return upper_bound(begin(v), end(v), x) - begin(v) - 1; } @@ -383,7 +389,6 @@ template class OfflineBIT2D { for (int i = 1; i <= n; i++) { bit[i].resize(vals[i].size()); } } - /** adds val to the point (r, c) */ void add(int r, int c, T val) { r++, c++; for (; r <= n; r += r & -r) { @@ -392,7 +397,6 @@ template class OfflineBIT2D { } } - /** @returns sum of points with row in [0, r] and column in [0, c] */ T rect_sum(int r, int c) { r++, c++; T sum = 0; @@ -403,7 +407,6 @@ template class OfflineBIT2D { return sum; } - /** @returns sum of points with r in [r1, r2] and c in [c1, c2] */ T rect_sum(int r1, int c1, int r2, int c2) { return rect_sum(r2, c2) - rect_sum(r2, c1 - 1) - rect_sum(r1 - 1, c2) + rect_sum(r1 - 1, c1 - 1); From fb24d5563b5e0ba8403c83eea51cc4ff3ec146da Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 28 Sep 2024 18:37:40 +0000 Subject: [PATCH 10/10] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- content/5_Plat/2DRQ.mdx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/content/5_Plat/2DRQ.mdx b/content/5_Plat/2DRQ.mdx index 32c9514274..90529045d0 100644 --- a/content/5_Plat/2DRQ.mdx +++ b/content/5_Plat/2DRQ.mdx @@ -50,8 +50,8 @@ query subrectangles. ```cpp -#include #include +#include using namespace std; /** @@ -277,10 +277,10 @@ easier to understand, albeit significantly slower due to a high constant factor: ```cpp -#include -#include #include #include +#include +#include using namespace std; /** @@ -354,10 +354,10 @@ And you might use it like so: ```cpp -#include -#include #include #include +#include +#include using namespace std; using ll = long long;