From 0160020bf7c8d5198fb189d2ee74eb10c6933157 Mon Sep 17 00:00:00 2001
From: TheGamingMousse <68484800+TheGamingMousse@users.noreply.github.com>
Date: Fri, 3 May 2024 16:11:16 -0700
Subject: [PATCH 01/23] wrote the stuff
---
content/5_Plat/Binary_Jump.problems.json | 3 +-
solutions/platinum/bts-hotcold.mdx | 189 +++++++++++++++++++++++
2 files changed, 190 insertions(+), 2 deletions(-)
create mode 100644 solutions/platinum/bts-hotcold.mdx
diff --git a/content/5_Plat/Binary_Jump.problems.json b/content/5_Plat/Binary_Jump.problems.json
index 34041d5588..ecce628300 100644
--- a/content/5_Plat/Binary_Jump.problems.json
+++ b/content/5_Plat/Binary_Jump.problems.json
@@ -347,8 +347,7 @@
"isStarred": false,
"tags": ["LCA"],
"solutionMetadata": {
- "kind": "autogen-label-from-site",
- "site": "DMOJ"
+ "kind": "internal"
}
},
{
diff --git a/solutions/platinum/bts-hotcold.mdx b/solutions/platinum/bts-hotcold.mdx
new file mode 100644
index 0000000000..cdb4f84fd3
--- /dev/null
+++ b/solutions/platinum/bts-hotcold.mdx
@@ -0,0 +1,189 @@
+---
+id: bts-hotcold
+source: Back to School 2017
+title: Hot & Cold
+author: Justin Ji
+---
+
+## Explanation
+
+Let $a$, $b$, and $t$ be the nodes given in each query, and $p$ be
+the LCA of $a$ and $b$. Directly updating the path from $a$
+to $b$ is difficult to do, so breaking up the path into smaller segments
+is necessary. To do that, we use some casework.
+
+**Case 1: $p$ is equal to $t$, or $t$ is not inside $p$'s subtree.**
+
+In this case, we just update the path from $a$ to $p$ and
+$b$ to $p$. Note that if $p$ is equal to either $a$ or $b$,
+then this case must be handled slightly differently.
+
+**Case 2: $p$ is equal to either $a$ or $b$.**
+
+Let the first ancestor of $t$ that is on the path from $a$ to $b$
+be $l$. WLOG, let $b$ be equal to $p$. Then, we update the path from
+$a$ to $l$ and the path from $l$ to $b$.
+
+**Case 3: The LCA of $t$ with $a$ and $b$ is the same as $p$.**
+
+Handle this case similarly to case 1.
+
+**Case 4: Either the LCA of $t$ and $a$ or the LCA of $t$ and $b$ lie on the path from $a$ to $b$.**
+
+In this case, split the path updates into 3 segments. Let the lower of the two LCAs mentioned
+be $l$, and the node which is an ancestor of $l$ be $a$. Then, just update the path from
+$a$ to $l$, $l$ to $p$, and the path from $b$ to $p$.
+
+**Handling Path Updates**
+
+Note that based on how we did our casework on the paths, that all path updates are between a given
+node and its ancestor. Also, note that the path updates are just adding distances which either increase
+or decrease by a fixed amount every time. So, we can sort of do a difference array on a tree, where we DFS
+down the tree and apply the differences while walking back up the tree.
+
+**Time Complexity:** $\mathcal{O}(N\log{N})$
+
+
+
+
+
+```cpp
+#include
+using namespace std;
+using ll = long long;
+
+int main() {
+ int n, s;
+ cin >> n >> s;
+ // 1 indexing makes updates easier
+ vector> adj(n + 1);
+ for (int i = 1; i < n; i++) {
+ int u, v;
+ cin >> u >> v;
+ adj[u].push_back(v);
+ adj[v].push_back(u);
+ }
+
+ // perform Euler tour and binary lifts
+ const int LOG = 1 + (int) log2(n);
+ vector> lift(LOG, vector(n + 1));
+ vector tin(n + 1);
+ vector tout(n + 1);
+ vector depth(n + 1);
+ int timer = 0;
+ function tour = [&](int u, int p) {
+ tin[u] = timer++;
+ lift[0][u] = p;
+ depth[u] = depth[p] + 1;
+ for (int i = 1; i < LOG; i++) {
+ lift[i][u] = lift[i - 1][lift[i - 1][u]];
+ }
+ for (int v : adj[u]) {
+ if (v != p) { tour(v, u); }
+ }
+ tout[u] = timer - 1;
+ };
+ tour(1, 0);
+ tin[0] = -1, tout[0] = n + 1; // so LCA works
+
+ // just some helper methods to simplify the code
+ auto isAnc = [&](int u, int v) -> bool {
+ return tin[u] <= tin[v] && tout[v] <= tout[u];
+ };
+ auto lca = [&](int u, int v) -> int {
+ if (isAnc(u, v)) return u;
+ if (isAnc(v, u)) return v;
+ for (int i = LOG - 1; i >= 0; i--) {
+ if (!isAnc(lift[i][u], v)) {
+ u = lift[i][u];
+ }
+ }
+ return lift[0][u];
+ };
+ auto dist = [&](int a, int b, int anc = -1) -> int {
+ if (anc == -1) { anc = lca(a, b); }
+ return depth[a] + depth[b] - 2 * depth[anc];
+ };
+
+ // calculating difference array updates
+ vector> diff(n + 1, {0, 0});
+ auto upd = [&](int u, int v, int initial, int change) -> void {
+ /*
+ * Precondition: v is an ancestor of u, or equal to u.
+ *
+ * Updates path from u to v, excluding v. When walking up from
+ * u to v, the added initial value is updated with the "change".
+ */
+ diff[u][0] += initial;
+ diff[u][1] += change;
+ if (change > 0) {
+ diff[v][0] -= initial + (depth[u] - depth[v]);
+ } else {
+ diff[v][0] -= initial - (depth[u] - depth[v]);
+ }
+ diff[v][1] -= change;
+ };
+ auto qry = [&](int a, int b, int t) -> void {
+ int anc = lca(a, b);
+ if (anc == t || !isAnc(anc, t)) {
+ // t is either the LCA, or not inside the subtree of the LCA
+ if (anc == a || anc == b) {
+ if (anc == a) { swap(a, b); }
+ upd(a, lift[0][b], dist(a, t), -1);
+ } else {
+ upd(a, anc, dist(a, t), -1);
+ upd(b, lift[0][anc], dist(b, t), -1);
+ }
+ } else {
+ // split_1 and split_2 are candidates for the locations where
+ // the path updates go from increasing to decreasing (or vice versa)
+ int split_1 = lca(a, t);
+ int split_2 = lca(b, t);
+ if (anc == a || anc == b) {
+ // path from a to be is just a walk upward
+ if (anc == a) {
+ swap(a, b);
+ swap(split_1, split_2);
+ }
+ upd(a, split_1, dist(a, t, split_1), -1);
+ upd(split_1, lift[0][b], dist(t, split_1, split_1), 1);
+ } else if (split_1 == anc && split_2 == anc) {
+ // lca(a, t) and lca(b, t) are both lca(a, b)
+ upd(a, anc, dist(a, t, anc), -1);
+ upd(b, lift[0][anc], dist(b, t, anc), -1);
+ } else {
+ // lca(a, b) != lca(a, t), or lca(a, b) != lca(b, t)
+ if (depth[split_1] < depth[split_2]) {
+ swap(split_1, split_2), swap(a, b);
+ }
+ upd(a, split_1, dist(a, t, split_1), -1);
+ upd(split_1, anc, dist(split_1, t, split_1), 1);
+ upd(b, lift[0][anc], dist(b, t, anc), -1);
+ }
+ }
+ };
+ while (s--) {
+ int a, b, t;
+ cin >> a >> b >> t;
+ qry(a, b, t);
+ }
+
+ // calculate the final result using the difference arrays
+ function dfs = [&](int u, int p) {
+ for (int v : adj[u]) {
+ if (v == p) { continue; }
+ dfs(v, u);
+ diff[u][0] += diff[v][0] + diff[v][1];
+ diff[u][1] += diff[v][1];
+ }
+ };
+ dfs(1, 0);
+ for (int i = 1; i <= n; i++) {
+ cout << diff[i][0] << " \n"[i == n];
+ }
+}
+```
+
+
+
+
\ No newline at end of file
From 248753ee18f88acaec8c8ae5f33fd6e8294ded44 Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Fri, 3 May 2024 23:16:04 +0000
Subject: [PATCH 02/23] [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---
solutions/platinum/bts-hotcold.mdx | 268 ++++++++++++++---------------
1 file changed, 132 insertions(+), 136 deletions(-)
diff --git a/solutions/platinum/bts-hotcold.mdx b/solutions/platinum/bts-hotcold.mdx
index cdb4f84fd3..b7e236bb4e 100644
--- a/solutions/platinum/bts-hotcold.mdx
+++ b/solutions/platinum/bts-hotcold.mdx
@@ -7,21 +7,21 @@ author: Justin Ji
## Explanation
-Let $a$, $b$, and $t$ be the nodes given in each query, and $p$ be
-the LCA of $a$ and $b$. Directly updating the path from $a$
+Let $a$, $b$, and $t$ be the nodes given in each query, and $p$ be
+the LCA of $a$ and $b$. Directly updating the path from $a$
to $b$ is difficult to do, so breaking up the path into smaller segments
is necessary. To do that, we use some casework.
**Case 1: $p$ is equal to $t$, or $t$ is not inside $p$'s subtree.**
-In this case, we just update the path from $a$ to $p$ and
+In this case, we just update the path from $a$ to $p$ and
$b$ to $p$. Note that if $p$ is equal to either $a$ or $b$,
then this case must be handled slightly differently.
**Case 2: $p$ is equal to either $a$ or $b$.**
Let the first ancestor of $t$ that is on the path from $a$ to $b$
-be $l$. WLOG, let $b$ be equal to $p$. Then, we update the path from
+be $l$. WLOG, let $b$ be equal to $p$. Then, we update the path from
$a$ to $l$ and the path from $l$ to $b$.
**Case 3: The LCA of $t$ with $a$ and $b$ is the same as $p$.**
@@ -31,14 +31,14 @@ Handle this case similarly to case 1.
**Case 4: Either the LCA of $t$ and $a$ or the LCA of $t$ and $b$ lie on the path from $a$ to $b$.**
In this case, split the path updates into 3 segments. Let the lower of the two LCAs mentioned
-be $l$, and the node which is an ancestor of $l$ be $a$. Then, just update the path from
+be $l$, and the node which is an ancestor of $l$ be $a$. Then, just update the path from
$a$ to $l$, $l$ to $p$, and the path from $b$ to $p$.
**Handling Path Updates**
Note that based on how we did our casework on the paths, that all path updates are between a given
-node and its ancestor. Also, note that the path updates are just adding distances which either increase
-or decrease by a fixed amount every time. So, we can sort of do a difference array on a tree, where we DFS
+node and its ancestor. Also, note that the path updates are just adding distances which either increase
+or decrease by a fixed amount every time. So, we can sort of do a difference array on a tree, where we DFS
down the tree and apply the differences while walking back up the tree.
**Time Complexity:** $\mathcal{O}(N\log{N})$
@@ -53,137 +53,133 @@ using namespace std;
using ll = long long;
int main() {
- int n, s;
- cin >> n >> s;
- // 1 indexing makes updates easier
- vector> adj(n + 1);
- for (int i = 1; i < n; i++) {
- int u, v;
- cin >> u >> v;
- adj[u].push_back(v);
- adj[v].push_back(u);
- }
-
- // perform Euler tour and binary lifts
- const int LOG = 1 + (int) log2(n);
- vector> lift(LOG, vector(n + 1));
- vector tin(n + 1);
- vector tout(n + 1);
- vector depth(n + 1);
- int timer = 0;
- function tour = [&](int u, int p) {
- tin[u] = timer++;
- lift[0][u] = p;
- depth[u] = depth[p] + 1;
- for (int i = 1; i < LOG; i++) {
- lift[i][u] = lift[i - 1][lift[i - 1][u]];
- }
- for (int v : adj[u]) {
- if (v != p) { tour(v, u); }
- }
- tout[u] = timer - 1;
- };
- tour(1, 0);
- tin[0] = -1, tout[0] = n + 1; // so LCA works
-
- // just some helper methods to simplify the code
- auto isAnc = [&](int u, int v) -> bool {
- return tin[u] <= tin[v] && tout[v] <= tout[u];
- };
- auto lca = [&](int u, int v) -> int {
- if (isAnc(u, v)) return u;
- if (isAnc(v, u)) return v;
- for (int i = LOG - 1; i >= 0; i--) {
- if (!isAnc(lift[i][u], v)) {
- u = lift[i][u];
- }
- }
- return lift[0][u];
- };
- auto dist = [&](int a, int b, int anc = -1) -> int {
- if (anc == -1) { anc = lca(a, b); }
- return depth[a] + depth[b] - 2 * depth[anc];
- };
-
- // calculating difference array updates
- vector> diff(n + 1, {0, 0});
- auto upd = [&](int u, int v, int initial, int change) -> void {
- /*
- * Precondition: v is an ancestor of u, or equal to u.
- *
- * Updates path from u to v, excluding v. When walking up from
- * u to v, the added initial value is updated with the "change".
- */
- diff[u][0] += initial;
- diff[u][1] += change;
- if (change > 0) {
- diff[v][0] -= initial + (depth[u] - depth[v]);
- } else {
- diff[v][0] -= initial - (depth[u] - depth[v]);
- }
- diff[v][1] -= change;
- };
- auto qry = [&](int a, int b, int t) -> void {
- int anc = lca(a, b);
- if (anc == t || !isAnc(anc, t)) {
- // t is either the LCA, or not inside the subtree of the LCA
- if (anc == a || anc == b) {
- if (anc == a) { swap(a, b); }
- upd(a, lift[0][b], dist(a, t), -1);
- } else {
- upd(a, anc, dist(a, t), -1);
- upd(b, lift[0][anc], dist(b, t), -1);
- }
- } else {
- // split_1 and split_2 are candidates for the locations where
- // the path updates go from increasing to decreasing (or vice versa)
- int split_1 = lca(a, t);
- int split_2 = lca(b, t);
- if (anc == a || anc == b) {
- // path from a to be is just a walk upward
- if (anc == a) {
- swap(a, b);
- swap(split_1, split_2);
- }
- upd(a, split_1, dist(a, t, split_1), -1);
- upd(split_1, lift[0][b], dist(t, split_1, split_1), 1);
- } else if (split_1 == anc && split_2 == anc) {
- // lca(a, t) and lca(b, t) are both lca(a, b)
- upd(a, anc, dist(a, t, anc), -1);
- upd(b, lift[0][anc], dist(b, t, anc), -1);
- } else {
- // lca(a, b) != lca(a, t), or lca(a, b) != lca(b, t)
- if (depth[split_1] < depth[split_2]) {
- swap(split_1, split_2), swap(a, b);
- }
- upd(a, split_1, dist(a, t, split_1), -1);
- upd(split_1, anc, dist(split_1, t, split_1), 1);
- upd(b, lift[0][anc], dist(b, t, anc), -1);
- }
- }
- };
- while (s--) {
- int a, b, t;
- cin >> a >> b >> t;
- qry(a, b, t);
- }
-
- // calculate the final result using the difference arrays
- function dfs = [&](int u, int p) {
- for (int v : adj[u]) {
- if (v == p) { continue; }
- dfs(v, u);
- diff[u][0] += diff[v][0] + diff[v][1];
- diff[u][1] += diff[v][1];
- }
- };
- dfs(1, 0);
- for (int i = 1; i <= n; i++) {
- cout << diff[i][0] << " \n"[i == n];
- }
+ int n, s;
+ cin >> n >> s;
+ // 1 indexing makes updates easier
+ vector> adj(n + 1);
+ for (int i = 1; i < n; i++) {
+ int u, v;
+ cin >> u >> v;
+ adj[u].push_back(v);
+ adj[v].push_back(u);
+ }
+
+ // perform Euler tour and binary lifts
+ const int LOG = 1 + (int)log2(n);
+ vector> lift(LOG, vector(n + 1));
+ vector tin(n + 1);
+ vector tout(n + 1);
+ vector depth(n + 1);
+ int timer = 0;
+ function tour = [&](int u, int p) {
+ tin[u] = timer++;
+ lift[0][u] = p;
+ depth[u] = depth[p] + 1;
+ for (int i = 1; i < LOG; i++) {
+ lift[i][u] = lift[i - 1][lift[i - 1][u]];
+ }
+ for (int v : adj[u]) {
+ if (v != p) { tour(v, u); }
+ }
+ tout[u] = timer - 1;
+ };
+ tour(1, 0);
+ tin[0] = -1, tout[0] = n + 1; // so LCA works
+
+ // just some helper methods to simplify the code
+ auto isAnc = [&](int u, int v) -> bool {
+ return tin[u] <= tin[v] && tout[v] <= tout[u];
+ };
+ auto lca = [&](int u, int v) -> int {
+ if (isAnc(u, v)) return u;
+ if (isAnc(v, u)) return v;
+ for (int i = LOG - 1; i >= 0; i--) {
+ if (!isAnc(lift[i][u], v)) { u = lift[i][u]; }
+ }
+ return lift[0][u];
+ };
+ auto dist = [&](int a, int b, int anc = -1) -> int {
+ if (anc == -1) { anc = lca(a, b); }
+ return depth[a] + depth[b] - 2 * depth[anc];
+ };
+
+ // calculating difference array updates
+ vector> diff(n + 1, {0, 0});
+ auto upd = [&](int u, int v, int initial, int change) -> void {
+ /*
+ * Precondition: v is an ancestor of u, or equal to u.
+ *
+ * Updates path from u to v, excluding v. When walking up from
+ * u to v, the added initial value is updated with the "change".
+ */
+ diff[u][0] += initial;
+ diff[u][1] += change;
+ if (change > 0) {
+ diff[v][0] -= initial + (depth[u] - depth[v]);
+ } else {
+ diff[v][0] -= initial - (depth[u] - depth[v]);
+ }
+ diff[v][1] -= change;
+ };
+ auto qry = [&](int a, int b, int t) -> void {
+ int anc = lca(a, b);
+ if (anc == t || !isAnc(anc, t)) {
+ // t is either the LCA, or not inside the subtree of the LCA
+ if (anc == a || anc == b) {
+ if (anc == a) { swap(a, b); }
+ upd(a, lift[0][b], dist(a, t), -1);
+ } else {
+ upd(a, anc, dist(a, t), -1);
+ upd(b, lift[0][anc], dist(b, t), -1);
+ }
+ } else {
+ // split_1 and split_2 are candidates for the locations where
+ // the path updates go from increasing to decreasing (or vice versa)
+ int split_1 = lca(a, t);
+ int split_2 = lca(b, t);
+ if (anc == a || anc == b) {
+ // path from a to be is just a walk upward
+ if (anc == a) {
+ swap(a, b);
+ swap(split_1, split_2);
+ }
+ upd(a, split_1, dist(a, t, split_1), -1);
+ upd(split_1, lift[0][b], dist(t, split_1, split_1), 1);
+ } else if (split_1 == anc && split_2 == anc) {
+ // lca(a, t) and lca(b, t) are both lca(a, b)
+ upd(a, anc, dist(a, t, anc), -1);
+ upd(b, lift[0][anc], dist(b, t, anc), -1);
+ } else {
+ // lca(a, b) != lca(a, t), or lca(a, b) != lca(b, t)
+ if (depth[split_1] < depth[split_2]) {
+ swap(split_1, split_2), swap(a, b);
+ }
+ upd(a, split_1, dist(a, t, split_1), -1);
+ upd(split_1, anc, dist(split_1, t, split_1), 1);
+ upd(b, lift[0][anc], dist(b, t, anc), -1);
+ }
+ }
+ };
+ while (s--) {
+ int a, b, t;
+ cin >> a >> b >> t;
+ qry(a, b, t);
+ }
+
+ // calculate the final result using the difference arrays
+ function dfs = [&](int u, int p) {
+ for (int v : adj[u]) {
+ if (v == p) { continue; }
+ dfs(v, u);
+ diff[u][0] += diff[v][0] + diff[v][1];
+ diff[u][1] += diff[v][1];
+ }
+ };
+ dfs(1, 0);
+ for (int i = 1; i <= n; i++) { cout << diff[i][0] << " \n"[i == n]; }
}
```
-
\ No newline at end of file
+
From 872a572c92e7f0c16b60b0c87df551dadf299161 Mon Sep 17 00:00:00 2001
From: TheGamingMousse <68484800+TheGamingMousse@users.noreply.github.com>
Date: Fri, 3 May 2024 19:57:34 -0700
Subject: [PATCH 03/23] did some style changes
---
solutions/platinum/bts-hotcold.mdx | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/solutions/platinum/bts-hotcold.mdx b/solutions/platinum/bts-hotcold.mdx
index cdb4f84fd3..5e957fa2aa 100644
--- a/solutions/platinum/bts-hotcold.mdx
+++ b/solutions/platinum/bts-hotcold.mdx
@@ -87,14 +87,14 @@ int main() {
tin[0] = -1, tout[0] = n + 1; // so LCA works
// just some helper methods to simplify the code
- auto isAnc = [&](int u, int v) -> bool {
+ auto isAncestor = [&](int u, int v) -> bool {
return tin[u] <= tin[v] && tout[v] <= tout[u];
};
auto lca = [&](int u, int v) -> int {
- if (isAnc(u, v)) return u;
- if (isAnc(v, u)) return v;
+ if (isAncestor(u, v)) { return u; }
+ if (isAncestor(v, u)) { return v; }
for (int i = LOG - 1; i >= 0; i--) {
- if (!isAnc(lift[i][u], v)) {
+ if (!isAncestor(lift[i][u], v)) {
u = lift[i][u];
}
}
@@ -125,7 +125,7 @@ int main() {
};
auto qry = [&](int a, int b, int t) -> void {
int anc = lca(a, b);
- if (anc == t || !isAnc(anc, t)) {
+ if (anc == t || !isAncestor(anc, t)) {
// t is either the LCA, or not inside the subtree of the LCA
if (anc == a || anc == b) {
if (anc == a) { swap(a, b); }
@@ -162,7 +162,7 @@ int main() {
}
}
};
- while (s--) {
+ for (int i = 0; i < s; i++) {
int a, b, t;
cin >> a >> b >> t;
qry(a, b, t);
From 3a57e62dae9e569d92f8c581b8f9bd2d3d6f9367 Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Sat, 4 May 2024 03:02:18 +0000
Subject: [PATCH 04/23] [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---
solutions/platinum/bts-hotcold.mdx | 186 ++++++++++++++---------------
1 file changed, 91 insertions(+), 95 deletions(-)
diff --git a/solutions/platinum/bts-hotcold.mdx b/solutions/platinum/bts-hotcold.mdx
index 8cf5a5f419..74a766e960 100644
--- a/solutions/platinum/bts-hotcold.mdx
+++ b/solutions/platinum/bts-hotcold.mdx
@@ -86,101 +86,97 @@ int main() {
tour(1, 0);
tin[0] = -1, tout[0] = n + 1; // so LCA works
- // just some helper methods to simplify the code
- auto isAncestor = [&](int u, int v) -> bool {
- return tin[u] <= tin[v] && tout[v] <= tout[u];
- };
- auto lca = [&](int u, int v) -> int {
- if (isAncestor(u, v)) { return u; }
- if (isAncestor(v, u)) { return v; }
- for (int i = LOG - 1; i >= 0; i--) {
- if (!isAncestor(lift[i][u], v)) {
- u = lift[i][u];
- }
- }
- return lift[0][u];
- };
- auto dist = [&](int a, int b, int anc = -1) -> int {
- if (anc == -1) { anc = lca(a, b); }
- return depth[a] + depth[b] - 2 * depth[anc];
- };
-
- // calculating difference array updates
- vector> diff(n + 1, {0, 0});
- auto upd = [&](int u, int v, int initial, int change) -> void {
- /*
- * Precondition: v is an ancestor of u, or equal to u.
- *
- * Updates path from u to v, excluding v. When walking up from
- * u to v, the added initial value is updated with the "change".
- */
- diff[u][0] += initial;
- diff[u][1] += change;
- if (change > 0) {
- diff[v][0] -= initial + (depth[u] - depth[v]);
- } else {
- diff[v][0] -= initial - (depth[u] - depth[v]);
- }
- diff[v][1] -= change;
- };
- auto qry = [&](int a, int b, int t) -> void {
- int anc = lca(a, b);
- if (anc == t || !isAncestor(anc, t)) {
- // t is either the LCA, or not inside the subtree of the LCA
- if (anc == a || anc == b) {
- if (anc == a) { swap(a, b); }
- upd(a, lift[0][b], dist(a, t), -1);
- } else {
- upd(a, anc, dist(a, t), -1);
- upd(b, lift[0][anc], dist(b, t), -1);
- }
- } else {
- // split_1 and split_2 are candidates for the locations where
- // the path updates go from increasing to decreasing (or vice versa)
- int split_1 = lca(a, t);
- int split_2 = lca(b, t);
- if (anc == a || anc == b) {
- // path from a to be is just a walk upward
- if (anc == a) {
- swap(a, b);
- swap(split_1, split_2);
- }
- upd(a, split_1, dist(a, t, split_1), -1);
- upd(split_1, lift[0][b], dist(t, split_1, split_1), 1);
- } else if (split_1 == anc && split_2 == anc) {
- // lca(a, t) and lca(b, t) are both lca(a, b)
- upd(a, anc, dist(a, t, anc), -1);
- upd(b, lift[0][anc], dist(b, t, anc), -1);
- } else {
- // lca(a, b) != lca(a, t), or lca(a, b) != lca(b, t)
- if (depth[split_1] < depth[split_2]) {
- swap(split_1, split_2), swap(a, b);
- }
- upd(a, split_1, dist(a, t, split_1), -1);
- upd(split_1, anc, dist(split_1, t, split_1), 1);
- upd(b, lift[0][anc], dist(b, t, anc), -1);
- }
- }
- };
- for (int i = 0; i < s; i++) {
- int a, b, t;
- cin >> a >> b >> t;
- qry(a, b, t);
- }
-
- // calculate the final result using the difference arrays
- function dfs = [&](int u, int p) {
- for (int v : adj[u]) {
- if (v == p) { continue; }
- dfs(v, u);
- diff[u][0] += diff[v][0] + diff[v][1];
- diff[u][1] += diff[v][1];
- }
- };
- dfs(1, 0);
- for (int i = 1; i <= n; i++) {
- cout << diff[i][0] << " \n"[i == n];
- }
+ // just some helper methods to simplify the code
+ auto isAncestor = [&](int u, int v) -> bool {
+ return tin[u] <= tin[v] && tout[v] <= tout[u];
+ };
+ auto lca = [&](int u, int v) -> int {
+ if (isAncestor(u, v)) { return u; }
+ if (isAncestor(v, u)) { return v; }
+ for (int i = LOG - 1; i >= 0; i--) {
+ if (!isAncestor(lift[i][u], v)) { u = lift[i][u]; }
+ }
+ return lift[0][u];
+ };
+ auto dist = [&](int a, int b, int anc = -1) -> int {
+ if (anc == -1) { anc = lca(a, b); }
+ return depth[a] + depth[b] - 2 * depth[anc];
+ };
+
+ // calculating difference array updates
+ vector> diff(n + 1, {0, 0});
+ auto upd = [&](int u, int v, int initial, int change) -> void {
+ /*
+ * Precondition: v is an ancestor of u, or equal to u.
+ *
+ * Updates path from u to v, excluding v. When walking up from
+ * u to v, the added initial value is updated with the "change".
+ */
+ diff[u][0] += initial;
+ diff[u][1] += change;
+ if (change > 0) {
+ diff[v][0] -= initial + (depth[u] - depth[v]);
+ } else {
+ diff[v][0] -= initial - (depth[u] - depth[v]);
+ }
+ diff[v][1] -= change;
+ };
+ auto qry = [&](int a, int b, int t) -> void {
+ int anc = lca(a, b);
+ if (anc == t || !isAncestor(anc, t)) {
+ // t is either the LCA, or not inside the subtree of the LCA
+ if (anc == a || anc == b) {
+ if (anc == a) { swap(a, b); }
+ upd(a, lift[0][b], dist(a, t), -1);
+ } else {
+ upd(a, anc, dist(a, t), -1);
+ upd(b, lift[0][anc], dist(b, t), -1);
+ }
+ } else {
+ // split_1 and split_2 are candidates for the locations where
+ // the path updates go from increasing to decreasing (or vice versa)
+ int split_1 = lca(a, t);
+ int split_2 = lca(b, t);
+ if (anc == a || anc == b) {
+ // path from a to be is just a walk upward
+ if (anc == a) {
+ swap(a, b);
+ swap(split_1, split_2);
+ }
+ upd(a, split_1, dist(a, t, split_1), -1);
+ upd(split_1, lift[0][b], dist(t, split_1, split_1), 1);
+ } else if (split_1 == anc && split_2 == anc) {
+ // lca(a, t) and lca(b, t) are both lca(a, b)
+ upd(a, anc, dist(a, t, anc), -1);
+ upd(b, lift[0][anc], dist(b, t, anc), -1);
+ } else {
+ // lca(a, b) != lca(a, t), or lca(a, b) != lca(b, t)
+ if (depth[split_1] < depth[split_2]) {
+ swap(split_1, split_2), swap(a, b);
+ }
+ upd(a, split_1, dist(a, t, split_1), -1);
+ upd(split_1, anc, dist(split_1, t, split_1), 1);
+ upd(b, lift[0][anc], dist(b, t, anc), -1);
+ }
+ }
+ };
+ for (int i = 0; i < s; i++) {
+ int a, b, t;
+ cin >> a >> b >> t;
+ qry(a, b, t);
+ }
+
+ // calculate the final result using the difference arrays
+ function dfs = [&](int u, int p) {
+ for (int v : adj[u]) {
+ if (v == p) { continue; }
+ dfs(v, u);
+ diff[u][0] += diff[v][0] + diff[v][1];
+ diff[u][1] += diff[v][1];
+ }
+ };
+ dfs(1, 0);
+ for (int i = 1; i <= n; i++) { cout << diff[i][0] << " \n"[i == n]; }
}
```
From 518b7c35059b85b74c7c1d438052ff898ab34c64 Mon Sep 17 00:00:00 2001
From: SansPapyrus683 <55369003+SansPapyrus683@users.noreply.github.com>
Date: Fri, 3 May 2024 20:26:20 -0700
Subject: [PATCH 05/23] Update bts-hotcold.mdx
---
solutions/platinum/bts-hotcold.mdx | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/solutions/platinum/bts-hotcold.mdx b/solutions/platinum/bts-hotcold.mdx
index 74a766e960..9f4ca4e042 100644
--- a/solutions/platinum/bts-hotcold.mdx
+++ b/solutions/platinum/bts-hotcold.mdx
@@ -34,17 +34,18 @@ In this case, split the path updates into 3 segments. Let the lower of the two L
be $l$, and the node which is an ancestor of $l$ be $a$. Then, just update the path from
$a$ to $l$, $l$ to $p$, and the path from $b$ to $p$.
-**Handling Path Updates**
+### Handling Path Updates
Note that based on how we did our casework on the paths, that all path updates are between a given
node and its ancestor. Also, note that the path updates are just adding distances which either increase
or decrease by a fixed amount every time. So, we can sort of do a difference array on a tree, where we DFS
down the tree and apply the differences while walking back up the tree.
+## Implementation
+
**Time Complexity:** $\mathcal{O}(N\log{N})$
-
```cpp
@@ -181,5 +182,4 @@ int main() {
```
-
From 58ae5f1413bd1745ae31bf6713df634409f4f077 Mon Sep 17 00:00:00 2001
From: TheGamingMousse <68484800+TheGamingMousse@users.noreply.github.com>
Date: Fri, 3 May 2024 21:22:20 -0700
Subject: [PATCH 06/23] put everything into a class
---
solutions/platinum/bts-hotcold.mdx | 261 +++++++++++++++--------------
1 file changed, 135 insertions(+), 126 deletions(-)
diff --git a/solutions/platinum/bts-hotcold.mdx b/solutions/platinum/bts-hotcold.mdx
index 9f4ca4e042..1392765ebd 100644
--- a/solutions/platinum/bts-hotcold.mdx
+++ b/solutions/platinum/bts-hotcold.mdx
@@ -14,7 +14,7 @@ is necessary. To do that, we use some casework.
**Case 1: $p$ is equal to $t$, or $t$ is not inside $p$'s subtree.**
-In this case, we just update the path from $a$ to $p$ and
+In this case, we update the path from $a$ to $p$ and
$b$ to $p$. Note that if $p$ is equal to either $a$ or $b$,
then this case must be handled slightly differently.
@@ -26,7 +26,8 @@ $a$ to $l$ and the path from $l$ to $b$.
**Case 3: The LCA of $t$ with $a$ and $b$ is the same as $p$.**
-Handle this case similarly to case 1.
+Like how we handled case 1, for this case we update the path from $a$ to
+$p$ and the path from $b$ to $p$.
**Case 4: Either the LCA of $t$ and $a$ or the LCA of $t$ and $b$ lie on the path from $a$ to $b$.**
@@ -53,131 +54,139 @@ down the tree and apply the differences while walking back up the tree.
using namespace std;
using ll = long long;
+class Tree {
+ private:
+ const int n, LOG;
+ vector> adj, lift;
+ vector depth, tin, tout;
+ vector> diff;
+ int timer = 0;
+ public:
+ Tree(int _n) : n(_n), LOG((int) log2(n) + 1), adj(n),
+ lift(LOG, vector(n)), depth(n),
+ tin(n), tout(n), diff(n) {
+ tin[0] = -1;
+ tout[0] = n + 1;
+ // ^ ensures that LCA works
+ }
+ void addEdge(int u, int v) {
+ adj[u].push_back(v);
+ adj[v].push_back(u);
+ }
+ void build(int u, int p) {
+ tin[u] = timer++;
+ lift[0][u] = p;
+ depth[u] = depth[p] + 1;
+ for (int i = 1; i < LOG; i++) {
+ lift[i][u] = lift[i - 1][lift[i - 1][u]];
+ }
+ for (int v : adj[u]) {
+ if (v != p) { build(v, u); }
+ }
+ tout[u] = timer - 1;
+ }
+ bool isAncestor(int u, int v) {
+ return tin[u] <= tin[v] && tout[v] <= tout[u];
+ }
+ int lca(int u, int v) {
+ if (isAncestor(u, v)) { return u; }
+ if (isAncestor(v, u)) { return v; }
+ for (int i = LOG - 1; i >= 0; i--) {
+ if (!isAncestor(lift[i][u], v)) {
+ u = lift[i][u];
+ }
+ }
+ return lift[0][u];
+ }
+ int dist(int u, int v, int anc = -1) {
+ if (anc == -1) { anc = lca(u, v); }
+ return depth[u] + depth[v] - 2 * depth[anc];
+ }
+ void update(int u, int v, int initial, int change) {
+ diff[u][0] += initial;
+ diff[u][1] += change;
+ if (change > 0) {
+ diff[v][0] -= initial + (depth[u] - depth[v]);
+ } else {
+ diff[v][0] -= initial - (depth[u] - depth[v]);
+ }
+ diff[v][1] -= change;
+ }
+ void query(int a, int b, int t) {
+ int anc = lca(a, b);
+ if (anc == t || !isAncestor(anc, t)) {
+ // t is either the LCA, or not inside the subtree of the LCA
+ if (anc == a || anc == b) {
+ if (anc == a) { swap(a, b); }
+ update(a, lift[0][b], dist(a, t), -1);
+ } else {
+ update(a, anc, dist(a, t), -1);
+ update(b, lift[0][anc], dist(b, t), -1);
+ }
+ } else {
+ // split_1 and split_2 are candidates for the locations where
+ // the path updates go from increasing to decreasing (or vice versa)
+ int split_1 = lca(a, t);
+ int split_2 = lca(b, t);
+ if (anc == a || anc == b) {
+ // path from a to be is just a walk upward
+ if (anc == a) {
+ swap(a, b);
+ swap(split_1, split_2);
+ }
+ update(a, split_1, dist(a, t, split_1), -1);
+ update(split_1, lift[0][b], dist(t, split_1, split_1), 1);
+ } else if (split_1 == anc && split_2 == anc) {
+ // lca(a, t) and lca(b, t) are both lca(a, b)
+ update(a, anc, dist(a, t, anc), -1);
+ update(b, lift[0][anc], dist(b, t, anc), -1);
+ } else {
+ // lca(a, b) != lca(a, t), or lca(a, b) != lca(b, t)
+ if (depth[split_1] < depth[split_2]) {
+ swap(split_1, split_2), swap(a, b);
+ }
+ update(a, split_1, dist(a, t, split_1), -1);
+ update(split_1, anc, dist(split_1, t, split_1), 1);
+ update(b, lift[0][anc], dist(b, t, anc), -1);
+ }
+ }
+ }
+ void dfs(int u, int p) {
+ for (int v : adj[u]) {
+ if (v == p) { continue; }
+ dfs(v, u);
+ diff[u][0] += diff[v][0] + diff[v][1];
+ diff[u][1] += diff[v][1];
+ }
+ }
+ vector result() {
+ dfs(1, 0);
+ vector res(n + 1);
+ for (int i = 1; i <= n; i++) {
+ res[i] = diff[i][0];
+ }
+ return res;
+ }
+};
int main() {
- int n, s;
- cin >> n >> s;
- // 1 indexing makes updates easier
- vector> adj(n + 1);
- for (int i = 1; i < n; i++) {
- int u, v;
- cin >> u >> v;
- adj[u].push_back(v);
- adj[v].push_back(u);
- }
-
- // perform Euler tour and binary lifts
- const int LOG = 1 + (int)log2(n);
- vector> lift(LOG, vector(n + 1));
- vector tin(n + 1);
- vector tout(n + 1);
- vector depth(n + 1);
- int timer = 0;
- function tour = [&](int u, int p) {
- tin[u] = timer++;
- lift[0][u] = p;
- depth[u] = depth[p] + 1;
- for (int i = 1; i < LOG; i++) {
- lift[i][u] = lift[i - 1][lift[i - 1][u]];
- }
- for (int v : adj[u]) {
- if (v != p) { tour(v, u); }
- }
- tout[u] = timer - 1;
- };
- tour(1, 0);
- tin[0] = -1, tout[0] = n + 1; // so LCA works
-
- // just some helper methods to simplify the code
- auto isAncestor = [&](int u, int v) -> bool {
- return tin[u] <= tin[v] && tout[v] <= tout[u];
- };
- auto lca = [&](int u, int v) -> int {
- if (isAncestor(u, v)) { return u; }
- if (isAncestor(v, u)) { return v; }
- for (int i = LOG - 1; i >= 0; i--) {
- if (!isAncestor(lift[i][u], v)) { u = lift[i][u]; }
- }
- return lift[0][u];
- };
- auto dist = [&](int a, int b, int anc = -1) -> int {
- if (anc == -1) { anc = lca(a, b); }
- return depth[a] + depth[b] - 2 * depth[anc];
- };
-
- // calculating difference array updates
- vector> diff(n + 1, {0, 0});
- auto upd = [&](int u, int v, int initial, int change) -> void {
- /*
- * Precondition: v is an ancestor of u, or equal to u.
- *
- * Updates path from u to v, excluding v. When walking up from
- * u to v, the added initial value is updated with the "change".
- */
- diff[u][0] += initial;
- diff[u][1] += change;
- if (change > 0) {
- diff[v][0] -= initial + (depth[u] - depth[v]);
- } else {
- diff[v][0] -= initial - (depth[u] - depth[v]);
- }
- diff[v][1] -= change;
- };
- auto qry = [&](int a, int b, int t) -> void {
- int anc = lca(a, b);
- if (anc == t || !isAncestor(anc, t)) {
- // t is either the LCA, or not inside the subtree of the LCA
- if (anc == a || anc == b) {
- if (anc == a) { swap(a, b); }
- upd(a, lift[0][b], dist(a, t), -1);
- } else {
- upd(a, anc, dist(a, t), -1);
- upd(b, lift[0][anc], dist(b, t), -1);
- }
- } else {
- // split_1 and split_2 are candidates for the locations where
- // the path updates go from increasing to decreasing (or vice versa)
- int split_1 = lca(a, t);
- int split_2 = lca(b, t);
- if (anc == a || anc == b) {
- // path from a to be is just a walk upward
- if (anc == a) {
- swap(a, b);
- swap(split_1, split_2);
- }
- upd(a, split_1, dist(a, t, split_1), -1);
- upd(split_1, lift[0][b], dist(t, split_1, split_1), 1);
- } else if (split_1 == anc && split_2 == anc) {
- // lca(a, t) and lca(b, t) are both lca(a, b)
- upd(a, anc, dist(a, t, anc), -1);
- upd(b, lift[0][anc], dist(b, t, anc), -1);
- } else {
- // lca(a, b) != lca(a, t), or lca(a, b) != lca(b, t)
- if (depth[split_1] < depth[split_2]) {
- swap(split_1, split_2), swap(a, b);
- }
- upd(a, split_1, dist(a, t, split_1), -1);
- upd(split_1, anc, dist(split_1, t, split_1), 1);
- upd(b, lift[0][anc], dist(b, t, anc), -1);
- }
- }
- };
- for (int i = 0; i < s; i++) {
- int a, b, t;
- cin >> a >> b >> t;
- qry(a, b, t);
- }
-
- // calculate the final result using the difference arrays
- function dfs = [&](int u, int p) {
- for (int v : adj[u]) {
- if (v == p) { continue; }
- dfs(v, u);
- diff[u][0] += diff[v][0] + diff[v][1];
- diff[u][1] += diff[v][1];
- }
- };
- dfs(1, 0);
- for (int i = 1; i <= n; i++) { cout << diff[i][0] << " \n"[i == n]; }
+ int n, s;
+ cin >> n >> s;
+ Tree tree(n + 1);
+ for (int i = 1; i < n; i++) {
+ int u, v;
+ cin >> u >> v;
+ tree.addEdge(u, v);
+ }
+ tree.build(1, 0);
+ for (int i = 0; i < s; i++) {
+ int a, b, t;
+ cin >> a >> b >> t;
+ tree.query(a, b, t);
+ }
+ vector res = tree.result();
+ for (int i = 1; i <= n; i++) {
+ cout << res[i] << " \n"[i == n];
+ }
}
```
From fd3a169c7619ca3a33e6f57948aff9818c5864e6 Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Sat, 4 May 2024 04:23:29 +0000
Subject: [PATCH 07/23] [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---
solutions/platinum/bts-hotcold.mdx | 255 ++++++++++++++---------------
1 file changed, 125 insertions(+), 130 deletions(-)
diff --git a/solutions/platinum/bts-hotcold.mdx b/solutions/platinum/bts-hotcold.mdx
index 1392765ebd..ac2394779d 100644
--- a/solutions/platinum/bts-hotcold.mdx
+++ b/solutions/platinum/bts-hotcold.mdx
@@ -55,138 +55,133 @@ using namespace std;
using ll = long long;
class Tree {
- private:
- const int n, LOG;
- vector> adj, lift;
- vector depth, tin, tout;
- vector> diff;
- int timer = 0;
- public:
- Tree(int _n) : n(_n), LOG((int) log2(n) + 1), adj(n),
- lift(LOG, vector(n)), depth(n),
- tin(n), tout(n), diff(n) {
- tin[0] = -1;
- tout[0] = n + 1;
- // ^ ensures that LCA works
- }
- void addEdge(int u, int v) {
- adj[u].push_back(v);
- adj[v].push_back(u);
- }
- void build(int u, int p) {
- tin[u] = timer++;
- lift[0][u] = p;
- depth[u] = depth[p] + 1;
- for (int i = 1; i < LOG; i++) {
- lift[i][u] = lift[i - 1][lift[i - 1][u]];
- }
- for (int v : adj[u]) {
- if (v != p) { build(v, u); }
- }
- tout[u] = timer - 1;
- }
- bool isAncestor(int u, int v) {
- return tin[u] <= tin[v] && tout[v] <= tout[u];
- }
- int lca(int u, int v) {
- if (isAncestor(u, v)) { return u; }
- if (isAncestor(v, u)) { return v; }
- for (int i = LOG - 1; i >= 0; i--) {
- if (!isAncestor(lift[i][u], v)) {
- u = lift[i][u];
- }
- }
- return lift[0][u];
- }
- int dist(int u, int v, int anc = -1) {
- if (anc == -1) { anc = lca(u, v); }
- return depth[u] + depth[v] - 2 * depth[anc];
- }
- void update(int u, int v, int initial, int change) {
- diff[u][0] += initial;
- diff[u][1] += change;
- if (change > 0) {
- diff[v][0] -= initial + (depth[u] - depth[v]);
- } else {
- diff[v][0] -= initial - (depth[u] - depth[v]);
- }
- diff[v][1] -= change;
- }
- void query(int a, int b, int t) {
- int anc = lca(a, b);
- if (anc == t || !isAncestor(anc, t)) {
- // t is either the LCA, or not inside the subtree of the LCA
- if (anc == a || anc == b) {
- if (anc == a) { swap(a, b); }
- update(a, lift[0][b], dist(a, t), -1);
- } else {
- update(a, anc, dist(a, t), -1);
- update(b, lift[0][anc], dist(b, t), -1);
- }
- } else {
- // split_1 and split_2 are candidates for the locations where
- // the path updates go from increasing to decreasing (or vice versa)
- int split_1 = lca(a, t);
- int split_2 = lca(b, t);
- if (anc == a || anc == b) {
- // path from a to be is just a walk upward
- if (anc == a) {
- swap(a, b);
- swap(split_1, split_2);
- }
- update(a, split_1, dist(a, t, split_1), -1);
- update(split_1, lift[0][b], dist(t, split_1, split_1), 1);
- } else if (split_1 == anc && split_2 == anc) {
- // lca(a, t) and lca(b, t) are both lca(a, b)
- update(a, anc, dist(a, t, anc), -1);
- update(b, lift[0][anc], dist(b, t, anc), -1);
- } else {
- // lca(a, b) != lca(a, t), or lca(a, b) != lca(b, t)
- if (depth[split_1] < depth[split_2]) {
- swap(split_1, split_2), swap(a, b);
- }
- update(a, split_1, dist(a, t, split_1), -1);
- update(split_1, anc, dist(split_1, t, split_1), 1);
- update(b, lift[0][anc], dist(b, t, anc), -1);
- }
- }
- }
- void dfs(int u, int p) {
- for (int v : adj[u]) {
- if (v == p) { continue; }
- dfs(v, u);
- diff[u][0] += diff[v][0] + diff[v][1];
- diff[u][1] += diff[v][1];
- }
- }
- vector result() {
- dfs(1, 0);
- vector res(n + 1);
- for (int i = 1; i <= n; i++) {
- res[i] = diff[i][0];
- }
- return res;
- }
+ private:
+ const int n, LOG;
+ vector> adj, lift;
+ vector depth, tin, tout;
+ vector> diff;
+ int timer = 0;
+
+ public:
+ Tree(int _n)
+ : n(_n), LOG((int)log2(n) + 1), adj(n), lift(LOG, vector(n)),
+ depth(n), tin(n), tout(n), diff(n) {
+ tin[0] = -1;
+ tout[0] = n + 1;
+ // ^ ensures that LCA works
+ }
+ void addEdge(int u, int v) {
+ adj[u].push_back(v);
+ adj[v].push_back(u);
+ }
+ void build(int u, int p) {
+ tin[u] = timer++;
+ lift[0][u] = p;
+ depth[u] = depth[p] + 1;
+ for (int i = 1; i < LOG; i++) {
+ lift[i][u] = lift[i - 1][lift[i - 1][u]];
+ }
+ for (int v : adj[u]) {
+ if (v != p) { build(v, u); }
+ }
+ tout[u] = timer - 1;
+ }
+ bool isAncestor(int u, int v) {
+ return tin[u] <= tin[v] && tout[v] <= tout[u];
+ }
+ int lca(int u, int v) {
+ if (isAncestor(u, v)) { return u; }
+ if (isAncestor(v, u)) { return v; }
+ for (int i = LOG - 1; i >= 0; i--) {
+ if (!isAncestor(lift[i][u], v)) { u = lift[i][u]; }
+ }
+ return lift[0][u];
+ }
+ int dist(int u, int v, int anc = -1) {
+ if (anc == -1) { anc = lca(u, v); }
+ return depth[u] + depth[v] - 2 * depth[anc];
+ }
+ void update(int u, int v, int initial, int change) {
+ diff[u][0] += initial;
+ diff[u][1] += change;
+ if (change > 0) {
+ diff[v][0] -= initial + (depth[u] - depth[v]);
+ } else {
+ diff[v][0] -= initial - (depth[u] - depth[v]);
+ }
+ diff[v][1] -= change;
+ }
+ void query(int a, int b, int t) {
+ int anc = lca(a, b);
+ if (anc == t || !isAncestor(anc, t)) {
+ // t is either the LCA, or not inside the subtree of the LCA
+ if (anc == a || anc == b) {
+ if (anc == a) { swap(a, b); }
+ update(a, lift[0][b], dist(a, t), -1);
+ } else {
+ update(a, anc, dist(a, t), -1);
+ update(b, lift[0][anc], dist(b, t), -1);
+ }
+ } else {
+ // split_1 and split_2 are candidates for the locations where
+ // the path updates go from increasing to decreasing (or vice versa)
+ int split_1 = lca(a, t);
+ int split_2 = lca(b, t);
+ if (anc == a || anc == b) {
+ // path from a to be is just a walk upward
+ if (anc == a) {
+ swap(a, b);
+ swap(split_1, split_2);
+ }
+ update(a, split_1, dist(a, t, split_1), -1);
+ update(split_1, lift[0][b], dist(t, split_1, split_1), 1);
+ } else if (split_1 == anc && split_2 == anc) {
+ // lca(a, t) and lca(b, t) are both lca(a, b)
+ update(a, anc, dist(a, t, anc), -1);
+ update(b, lift[0][anc], dist(b, t, anc), -1);
+ } else {
+ // lca(a, b) != lca(a, t), or lca(a, b) != lca(b, t)
+ if (depth[split_1] < depth[split_2]) {
+ swap(split_1, split_2), swap(a, b);
+ }
+ update(a, split_1, dist(a, t, split_1), -1);
+ update(split_1, anc, dist(split_1, t, split_1), 1);
+ update(b, lift[0][anc], dist(b, t, anc), -1);
+ }
+ }
+ }
+ void dfs(int u, int p) {
+ for (int v : adj[u]) {
+ if (v == p) { continue; }
+ dfs(v, u);
+ diff[u][0] += diff[v][0] + diff[v][1];
+ diff[u][1] += diff[v][1];
+ }
+ }
+ vector result() {
+ dfs(1, 0);
+ vector res(n + 1);
+ for (int i = 1; i <= n; i++) { res[i] = diff[i][0]; }
+ return res;
+ }
};
int main() {
- int n, s;
- cin >> n >> s;
- Tree tree(n + 1);
- for (int i = 1; i < n; i++) {
- int u, v;
- cin >> u >> v;
- tree.addEdge(u, v);
- }
- tree.build(1, 0);
- for (int i = 0; i < s; i++) {
- int a, b, t;
- cin >> a >> b >> t;
- tree.query(a, b, t);
- }
- vector res = tree.result();
- for (int i = 1; i <= n; i++) {
- cout << res[i] << " \n"[i == n];
- }
+ int n, s;
+ cin >> n >> s;
+ Tree tree(n + 1);
+ for (int i = 1; i < n; i++) {
+ int u, v;
+ cin >> u >> v;
+ tree.addEdge(u, v);
+ }
+ tree.build(1, 0);
+ for (int i = 0; i < s; i++) {
+ int a, b, t;
+ cin >> a >> b >> t;
+ tree.query(a, b, t);
+ }
+ vector res = tree.result();
+ for (int i = 1; i <= n; i++) { cout << res[i] << " \n"[i == n]; }
}
```
From fbc2ae3929090218edabb92802c6891d014186c7 Mon Sep 17 00:00:00 2001
From: TheGamingMousse <68484800+TheGamingMousse@users.noreply.github.com>
Date: Sat, 4 May 2024 10:06:42 -0700
Subject: [PATCH 08/23] changed some stuff
---
solutions/platinum/bts-hotcold.mdx | 54 ++++++++++++++++++------------
1 file changed, 32 insertions(+), 22 deletions(-)
diff --git a/solutions/platinum/bts-hotcold.mdx b/solutions/platinum/bts-hotcold.mdx
index 1392765ebd..cff7f6f833 100644
--- a/solutions/platinum/bts-hotcold.mdx
+++ b/solutions/platinum/bts-hotcold.mdx
@@ -56,28 +56,30 @@ using ll = long long;
class Tree {
private:
- const int n, LOG;
- vector> adj, lift;
- vector depth, tin, tout;
+ const int n, log2dist;
+ vector> &adj;
+ vector> lift;
vector> diff;
+ vector depth;
+ vector tin;
+ vector tout;
int timer = 0;
public:
- Tree(int _n) : n(_n), LOG((int) log2(n) + 1), adj(n),
- lift(LOG, vector(n)), depth(n),
- tin(n), tout(n), diff(n) {
+ Tree(int n, vector> &adj)
+ : n(n), log2dist((int) log2(n) + 1), adj(adj),
+ lift(log2dist, vector(n)), depth(n),
+ tin(n), tout(n), diff(n) {
tin[0] = -1;
tout[0] = n + 1;
// ^ ensures that LCA works
+ build(1, 0);
}
- void addEdge(int u, int v) {
- adj[u].push_back(v);
- adj[v].push_back(u);
- }
+
void build(int u, int p) {
tin[u] = timer++;
lift[0][u] = p;
depth[u] = depth[p] + 1;
- for (int i = 1; i < LOG; i++) {
+ for (int i = 1; i < log2dist; i++) {
lift[i][u] = lift[i - 1][lift[i - 1][u]];
}
for (int v : adj[u]) {
@@ -85,23 +87,27 @@ class Tree {
}
tout[u] = timer - 1;
}
- bool isAncestor(int u, int v) {
+
+ bool is_ancestor(int u, int v) {
return tin[u] <= tin[v] && tout[v] <= tout[u];
}
+
int lca(int u, int v) {
- if (isAncestor(u, v)) { return u; }
- if (isAncestor(v, u)) { return v; }
- for (int i = LOG - 1; i >= 0; i--) {
- if (!isAncestor(lift[i][u], v)) {
+ if (is_ancestor(u, v)) { return u; }
+ if (is_ancestor(v, u)) { return v; }
+ for (int i = log2dist - 1; i >= 0; i--) {
+ if (!is_ancestor(lift[i][u], v)) {
u = lift[i][u];
}
}
return lift[0][u];
}
+
int dist(int u, int v, int anc = -1) {
if (anc == -1) { anc = lca(u, v); }
return depth[u] + depth[v] - 2 * depth[anc];
}
+
void update(int u, int v, int initial, int change) {
diff[u][0] += initial;
diff[u][1] += change;
@@ -112,9 +118,10 @@ class Tree {
}
diff[v][1] -= change;
}
+
void query(int a, int b, int t) {
int anc = lca(a, b);
- if (anc == t || !isAncestor(anc, t)) {
+ if (anc == t || !is_ancestor(anc, t)) {
// t is either the LCA, or not inside the subtree of the LCA
if (anc == a || anc == b) {
if (anc == a) { swap(a, b); }
@@ -151,6 +158,7 @@ class Tree {
}
}
}
+
void dfs(int u, int p) {
for (int v : adj[u]) {
if (v == p) { continue; }
@@ -159,7 +167,8 @@ class Tree {
diff[u][1] += diff[v][1];
}
}
- vector result() {
+
+ vector calculate_result() {
dfs(1, 0);
vector res(n + 1);
for (int i = 1; i <= n; i++) {
@@ -171,19 +180,20 @@ class Tree {
int main() {
int n, s;
cin >> n >> s;
- Tree tree(n + 1);
+ vector> adj(n + 1);
for (int i = 1; i < n; i++) {
int u, v;
cin >> u >> v;
- tree.addEdge(u, v);
+ adj[u].push_back(v);
+ adj[v].push_back(u);
}
- tree.build(1, 0);
+ Tree tree(n + 1, adj);
for (int i = 0; i < s; i++) {
int a, b, t;
cin >> a >> b >> t;
tree.query(a, b, t);
}
- vector res = tree.result();
+ vector res = tree.calculate_result();
for (int i = 1; i <= n; i++) {
cout << res[i] << " \n"[i == n];
}
From 073620d0dde64eec00184d55c73a80136d217c91 Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Sat, 4 May 2024 17:10:53 +0000
Subject: [PATCH 09/23] [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---
solutions/platinum/bts-hotcold.mdx | 274 ++++++++++++++---------------
1 file changed, 134 insertions(+), 140 deletions(-)
diff --git a/solutions/platinum/bts-hotcold.mdx b/solutions/platinum/bts-hotcold.mdx
index cff7f6f833..5da69f1ac9 100644
--- a/solutions/platinum/bts-hotcold.mdx
+++ b/solutions/platinum/bts-hotcold.mdx
@@ -55,148 +55,142 @@ using namespace std;
using ll = long long;
class Tree {
- private:
- const int n, log2dist;
- vector> &adj;
- vector> lift;
- vector> diff;
- vector depth;
- vector tin;
- vector tout;
- int timer = 0;
- public:
- Tree(int n, vector> &adj)
- : n(n), log2dist((int) log2(n) + 1), adj(adj),
- lift(log2dist, vector(n)), depth(n),
- tin(n), tout(n), diff(n) {
- tin[0] = -1;
- tout[0] = n + 1;
- // ^ ensures that LCA works
- build(1, 0);
- }
-
- void build(int u, int p) {
- tin[u] = timer++;
- lift[0][u] = p;
- depth[u] = depth[p] + 1;
- for (int i = 1; i < log2dist; i++) {
- lift[i][u] = lift[i - 1][lift[i - 1][u]];
- }
- for (int v : adj[u]) {
- if (v != p) { build(v, u); }
- }
- tout[u] = timer - 1;
- }
-
- bool is_ancestor(int u, int v) {
- return tin[u] <= tin[v] && tout[v] <= tout[u];
- }
-
- int lca(int u, int v) {
- if (is_ancestor(u, v)) { return u; }
- if (is_ancestor(v, u)) { return v; }
- for (int i = log2dist - 1; i >= 0; i--) {
- if (!is_ancestor(lift[i][u], v)) {
- u = lift[i][u];
- }
- }
- return lift[0][u];
- }
-
- int dist(int u, int v, int anc = -1) {
- if (anc == -1) { anc = lca(u, v); }
- return depth[u] + depth[v] - 2 * depth[anc];
- }
-
- void update(int u, int v, int initial, int change) {
- diff[u][0] += initial;
- diff[u][1] += change;
- if (change > 0) {
- diff[v][0] -= initial + (depth[u] - depth[v]);
- } else {
- diff[v][0] -= initial - (depth[u] - depth[v]);
- }
- diff[v][1] -= change;
- }
-
- void query(int a, int b, int t) {
- int anc = lca(a, b);
- if (anc == t || !is_ancestor(anc, t)) {
- // t is either the LCA, or not inside the subtree of the LCA
- if (anc == a || anc == b) {
- if (anc == a) { swap(a, b); }
- update(a, lift[0][b], dist(a, t), -1);
- } else {
- update(a, anc, dist(a, t), -1);
- update(b, lift[0][anc], dist(b, t), -1);
- }
- } else {
- // split_1 and split_2 are candidates for the locations where
- // the path updates go from increasing to decreasing (or vice versa)
- int split_1 = lca(a, t);
- int split_2 = lca(b, t);
- if (anc == a || anc == b) {
- // path from a to be is just a walk upward
- if (anc == a) {
- swap(a, b);
- swap(split_1, split_2);
- }
- update(a, split_1, dist(a, t, split_1), -1);
- update(split_1, lift[0][b], dist(t, split_1, split_1), 1);
- } else if (split_1 == anc && split_2 == anc) {
- // lca(a, t) and lca(b, t) are both lca(a, b)
- update(a, anc, dist(a, t, anc), -1);
- update(b, lift[0][anc], dist(b, t, anc), -1);
- } else {
- // lca(a, b) != lca(a, t), or lca(a, b) != lca(b, t)
- if (depth[split_1] < depth[split_2]) {
- swap(split_1, split_2), swap(a, b);
- }
- update(a, split_1, dist(a, t, split_1), -1);
- update(split_1, anc, dist(split_1, t, split_1), 1);
- update(b, lift[0][anc], dist(b, t, anc), -1);
- }
- }
- }
-
- void dfs(int u, int p) {
- for (int v : adj[u]) {
- if (v == p) { continue; }
- dfs(v, u);
- diff[u][0] += diff[v][0] + diff[v][1];
- diff[u][1] += diff[v][1];
- }
- }
-
- vector calculate_result() {
- dfs(1, 0);
- vector res(n + 1);
- for (int i = 1; i <= n; i++) {
- res[i] = diff[i][0];
- }
- return res;
- }
+ private:
+ const int n, log2dist;
+ vector> &adj;
+ vector> lift;
+ vector> diff;
+ vector depth;
+ vector tin;
+ vector tout;
+ int timer = 0;
+
+ public:
+ Tree(int n, vector> &adj)
+ : n(n), log2dist((int)log2(n) + 1), adj(adj),
+ lift(log2dist, vector(n)), depth(n), tin(n), tout(n), diff(n) {
+ tin[0] = -1;
+ tout[0] = n + 1;
+ // ^ ensures that LCA works
+ build(1, 0);
+ }
+
+ void build(int u, int p) {
+ tin[u] = timer++;
+ lift[0][u] = p;
+ depth[u] = depth[p] + 1;
+ for (int i = 1; i < log2dist; i++) {
+ lift[i][u] = lift[i - 1][lift[i - 1][u]];
+ }
+ for (int v : adj[u]) {
+ if (v != p) { build(v, u); }
+ }
+ tout[u] = timer - 1;
+ }
+
+ bool is_ancestor(int u, int v) {
+ return tin[u] <= tin[v] && tout[v] <= tout[u];
+ }
+
+ int lca(int u, int v) {
+ if (is_ancestor(u, v)) { return u; }
+ if (is_ancestor(v, u)) { return v; }
+ for (int i = log2dist - 1; i >= 0; i--) {
+ if (!is_ancestor(lift[i][u], v)) { u = lift[i][u]; }
+ }
+ return lift[0][u];
+ }
+
+ int dist(int u, int v, int anc = -1) {
+ if (anc == -1) { anc = lca(u, v); }
+ return depth[u] + depth[v] - 2 * depth[anc];
+ }
+
+ void update(int u, int v, int initial, int change) {
+ diff[u][0] += initial;
+ diff[u][1] += change;
+ if (change > 0) {
+ diff[v][0] -= initial + (depth[u] - depth[v]);
+ } else {
+ diff[v][0] -= initial - (depth[u] - depth[v]);
+ }
+ diff[v][1] -= change;
+ }
+
+ void query(int a, int b, int t) {
+ int anc = lca(a, b);
+ if (anc == t || !is_ancestor(anc, t)) {
+ // t is either the LCA, or not inside the subtree of the LCA
+ if (anc == a || anc == b) {
+ if (anc == a) { swap(a, b); }
+ update(a, lift[0][b], dist(a, t), -1);
+ } else {
+ update(a, anc, dist(a, t), -1);
+ update(b, lift[0][anc], dist(b, t), -1);
+ }
+ } else {
+ // split_1 and split_2 are candidates for the locations where
+ // the path updates go from increasing to decreasing (or vice versa)
+ int split_1 = lca(a, t);
+ int split_2 = lca(b, t);
+ if (anc == a || anc == b) {
+ // path from a to be is just a walk upward
+ if (anc == a) {
+ swap(a, b);
+ swap(split_1, split_2);
+ }
+ update(a, split_1, dist(a, t, split_1), -1);
+ update(split_1, lift[0][b], dist(t, split_1, split_1), 1);
+ } else if (split_1 == anc && split_2 == anc) {
+ // lca(a, t) and lca(b, t) are both lca(a, b)
+ update(a, anc, dist(a, t, anc), -1);
+ update(b, lift[0][anc], dist(b, t, anc), -1);
+ } else {
+ // lca(a, b) != lca(a, t), or lca(a, b) != lca(b, t)
+ if (depth[split_1] < depth[split_2]) {
+ swap(split_1, split_2), swap(a, b);
+ }
+ update(a, split_1, dist(a, t, split_1), -1);
+ update(split_1, anc, dist(split_1, t, split_1), 1);
+ update(b, lift[0][anc], dist(b, t, anc), -1);
+ }
+ }
+ }
+
+ void dfs(int u, int p) {
+ for (int v : adj[u]) {
+ if (v == p) { continue; }
+ dfs(v, u);
+ diff[u][0] += diff[v][0] + diff[v][1];
+ diff[u][1] += diff[v][1];
+ }
+ }
+
+ vector calculate_result() {
+ dfs(1, 0);
+ vector res(n + 1);
+ for (int i = 1; i <= n; i++) { res[i] = diff[i][0]; }
+ return res;
+ }
};
int main() {
- int n, s;
- cin >> n >> s;
- vector> adj(n + 1);
- for (int i = 1; i < n; i++) {
- int u, v;
- cin >> u >> v;
- adj[u].push_back(v);
- adj[v].push_back(u);
- }
- Tree tree(n + 1, adj);
- for (int i = 0; i < s; i++) {
- int a, b, t;
- cin >> a >> b >> t;
- tree.query(a, b, t);
- }
- vector res = tree.calculate_result();
- for (int i = 1; i <= n; i++) {
- cout << res[i] << " \n"[i == n];
- }
+ int n, s;
+ cin >> n >> s;
+ vector> adj(n + 1);
+ for (int i = 1; i < n; i++) {
+ int u, v;
+ cin >> u >> v;
+ adj[u].push_back(v);
+ adj[v].push_back(u);
+ }
+ Tree tree(n + 1, adj);
+ for (int i = 0; i < s; i++) {
+ int a, b, t;
+ cin >> a >> b >> t;
+ tree.query(a, b, t);
+ }
+ vector res = tree.calculate_result();
+ for (int i = 1; i <= n; i++) { cout << res[i] << " \n"[i == n]; }
}
```
From 9400b9be5a9a4fca2354cfff1c0a39a0bac17e0e Mon Sep 17 00:00:00 2001
From: SansPapyrus683 <55369003+SansPapyrus683@users.noreply.github.com>
Date: Sat, 4 May 2024 12:34:35 -0700
Subject: [PATCH 10/23] Update bts-hotcold.mdx
---
solutions/platinum/bts-hotcold.mdx | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/solutions/platinum/bts-hotcold.mdx b/solutions/platinum/bts-hotcold.mdx
index 5da69f1ac9..c2f63b9b7e 100644
--- a/solutions/platinum/bts-hotcold.mdx
+++ b/solutions/platinum/bts-hotcold.mdx
@@ -56,7 +56,8 @@ using ll = long long;
class Tree {
private:
- const int n, log2dist;
+ const int n;
+ const int log2dist;
vector> &adj;
vector> lift;
vector> diff;
@@ -173,22 +174,26 @@ class Tree {
return res;
}
};
+
int main() {
- int n, s;
+ int n;
+ int s;
cin >> n >> s;
vector> adj(n + 1);
- for (int i = 1; i < n; i++) {
+ for (int i = 0; i < n - 1; i++) {
int u, v;
cin >> u >> v;
adj[u].push_back(v);
adj[v].push_back(u);
}
+
Tree tree(n + 1, adj);
for (int i = 0; i < s; i++) {
int a, b, t;
cin >> a >> b >> t;
tree.query(a, b, t);
}
+
vector res = tree.calculate_result();
for (int i = 1; i <= n; i++) { cout << res[i] << " \n"[i == n]; }
}
From 281997c481e3e66ca65fb00948a37ab9778420da Mon Sep 17 00:00:00 2001
From: TheGamingMousse <68484800+TheGamingMousse@users.noreply.github.com>
Date: Sat, 4 May 2024 13:47:37 -0700
Subject: [PATCH 11/23] Update solutions/platinum/bts-hotcold.mdx
Co-authored-by: SansPapyrus683 <55369003+SansPapyrus683@users.noreply.github.com>
---
solutions/platinum/bts-hotcold.mdx | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/solutions/platinum/bts-hotcold.mdx b/solutions/platinum/bts-hotcold.mdx
index c2f63b9b7e..470f0f7bb4 100644
--- a/solutions/platinum/bts-hotcold.mdx
+++ b/solutions/platinum/bts-hotcold.mdx
@@ -71,8 +71,7 @@ class Tree {
: n(n), log2dist((int)log2(n) + 1), adj(adj),
lift(log2dist, vector(n)), depth(n), tin(n), tout(n), diff(n) {
tin[0] = -1;
- tout[0] = n + 1;
- // ^ ensures that LCA works
+ tout[0] = n + 1; // ensures that LCA works
build(1, 0);
}
From 8fb12fc1d6e481bba932435004d1de903414f0f0 Mon Sep 17 00:00:00 2001
From: TheGamingMousse <68484800+TheGamingMousse@users.noreply.github.com>
Date: Sat, 4 May 2024 13:48:50 -0700
Subject: [PATCH 12/23] Update solutions/platinum/bts-hotcold.mdx
Co-authored-by: SansPapyrus683 <55369003+SansPapyrus683@users.noreply.github.com>
---
solutions/platinum/bts-hotcold.mdx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/solutions/platinum/bts-hotcold.mdx b/solutions/platinum/bts-hotcold.mdx
index 470f0f7bb4..2fcecf51f4 100644
--- a/solutions/platinum/bts-hotcold.mdx
+++ b/solutions/platinum/bts-hotcold.mdx
@@ -59,7 +59,7 @@ class Tree {
const int n;
const int log2dist;
vector> &adj;
- vector> lift;
+ vector> lift; // for binary lifting
vector> diff;
vector depth;
vector tin;
From ee21978388fab8754c154f88e447e0e4f8612ec4 Mon Sep 17 00:00:00 2001
From: TheGamingMousse <68484800+TheGamingMousse@users.noreply.github.com>
Date: Sat, 4 May 2024 13:53:50 -0700
Subject: [PATCH 13/23] made constructor a bit more detailed n stuff
---
solutions/platinum/bts-hotcold.mdx | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/solutions/platinum/bts-hotcold.mdx b/solutions/platinum/bts-hotcold.mdx
index 2fcecf51f4..df3213bfc3 100644
--- a/solutions/platinum/bts-hotcold.mdx
+++ b/solutions/platinum/bts-hotcold.mdx
@@ -57,11 +57,13 @@ using ll = long long;
class Tree {
private:
const int n;
- const int log2dist;
- vector> &adj;
+ const int log2dist; // max height of the tree
+ vector> &adj; // reference to adjacency list
vector> lift; // for binary lifting
- vector> diff;
- vector depth;
+ vector> diff; // difference array updates
+ vector depth; // depth of each node
+
+ // these are for Euler tour
vector tin;
vector tout;
int timer = 0;
From cce5999985750992e23ce16859a6e46cb0578c7b Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Sat, 4 May 2024 20:55:03 +0000
Subject: [PATCH 14/23] [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---
solutions/platinum/bts-hotcold.mdx | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/solutions/platinum/bts-hotcold.mdx b/solutions/platinum/bts-hotcold.mdx
index df3213bfc3..8d5c734306 100644
--- a/solutions/platinum/bts-hotcold.mdx
+++ b/solutions/platinum/bts-hotcold.mdx
@@ -57,12 +57,12 @@ using ll = long long;
class Tree {
private:
const int n;
- const int log2dist; // max height of the tree
- vector> &adj; // reference to adjacency list
- vector> lift; // for binary lifting
- vector> diff; // difference array updates
- vector depth; // depth of each node
-
+ const int log2dist; // max height of the tree
+ vector> &adj; // reference to adjacency list
+ vector> lift; // for binary lifting
+ vector> diff; // difference array updates
+ vector depth; // depth of each node
+
// these are for Euler tour
vector tin;
vector tout;
From 73e0ec02fc0f90b178bee2fd6f75761a25c5814b Mon Sep 17 00:00:00 2001
From: TheGamingMousse <68484800+TheGamingMousse@users.noreply.github.com>
Date: Sat, 4 May 2024 16:22:33 -0700
Subject: [PATCH 15/23] Update bts-hotcold.mdx
---
solutions/platinum/bts-hotcold.mdx | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/solutions/platinum/bts-hotcold.mdx b/solutions/platinum/bts-hotcold.mdx
index 8d5c734306..674bd3022e 100644
--- a/solutions/platinum/bts-hotcold.mdx
+++ b/solutions/platinum/bts-hotcold.mdx
@@ -57,7 +57,7 @@ using ll = long long;
class Tree {
private:
const int n;
- const int log2dist; // max height of the tree
+ const int log2dist; // # of bits needed for binary lift
vector> &adj; // reference to adjacency list
vector> lift; // for binary lifting
vector> diff; // difference array updates
@@ -68,16 +68,7 @@ class Tree {
vector tout;
int timer = 0;
- public:
- Tree(int n, vector> &adj)
- : n(n), log2dist((int)log2(n) + 1), adj(adj),
- lift(log2dist, vector(n)), depth(n), tin(n), tout(n), diff(n) {
- tin[0] = -1;
- tout[0] = n + 1; // ensures that LCA works
- build(1, 0);
- }
-
- void build(int u, int p) {
+ void tour(int u, int p) {
tin[u] = timer++;
lift[0][u] = p;
depth[u] = depth[p] + 1;
@@ -85,11 +76,20 @@ class Tree {
lift[i][u] = lift[i - 1][lift[i - 1][u]];
}
for (int v : adj[u]) {
- if (v != p) { build(v, u); }
+ if (v != p) { tour(v, u); }
}
tout[u] = timer - 1;
}
+ public:
+ Tree(int n, vector> &adj)
+ : n(n), log2dist((int)log2(n) + 1), adj(adj),
+ lift(log2dist, vector(n)), diff(n), depth(n), tin(n), tout(n) {
+ tin[0] = -1;
+ tout[0] = n + 1; // ensures that LCA works
+ tour(1, 0);
+ }
+
bool is_ancestor(int u, int v) {
return tin[u] <= tin[v] && tout[v] <= tout[u];
}
From 26859fa8c6872dd35fd09fa0f5009cfeb2e1799f Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Sat, 4 May 2024 23:23:45 +0000
Subject: [PATCH 16/23] [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---
solutions/platinum/bts-hotcold.mdx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/solutions/platinum/bts-hotcold.mdx b/solutions/platinum/bts-hotcold.mdx
index 674bd3022e..654f995135 100644
--- a/solutions/platinum/bts-hotcold.mdx
+++ b/solutions/platinum/bts-hotcold.mdx
@@ -68,7 +68,7 @@ class Tree {
vector tout;
int timer = 0;
- void tour(int u, int p) {
+ void tour(int u, int p) {
tin[u] = timer++;
lift[0][u] = p;
depth[u] = depth[p] + 1;
From c3224b559f5c3d8f162494cf6b7052ed7cd423a9 Mon Sep 17 00:00:00 2001
From: SansPapyrus683 <55369003+SansPapyrus683@users.noreply.github.com>
Date: Sat, 4 May 2024 16:42:45 -0700
Subject: [PATCH 17/23] Update bts-hotcold.mdx
---
solutions/platinum/bts-hotcold.mdx | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/solutions/platinum/bts-hotcold.mdx b/solutions/platinum/bts-hotcold.mdx
index 654f995135..595fff8919 100644
--- a/solutions/platinum/bts-hotcold.mdx
+++ b/solutions/platinum/bts-hotcold.mdx
@@ -81,6 +81,15 @@ class Tree {
tout[u] = timer - 1;
}
+ void dfs(int u, int p) {
+ for (int v : adj[u]) {
+ if (v == p) { continue; }
+ dfs(v, u);
+ diff[u][0] += diff[v][0] + diff[v][1];
+ diff[u][1] += diff[v][1];
+ }
+ }
+
public:
Tree(int n, vector> &adj)
: n(n), log2dist((int)log2(n) + 1), adj(adj),
@@ -90,11 +99,11 @@ class Tree {
tour(1, 0);
}
- bool is_ancestor(int u, int v) {
+ bool is_ancestor(int u, int v) const {
return tin[u] <= tin[v] && tout[v] <= tout[u];
}
- int lca(int u, int v) {
+ int lca(int u, int v) const {
if (is_ancestor(u, v)) { return u; }
if (is_ancestor(v, u)) { return v; }
for (int i = log2dist - 1; i >= 0; i--) {
@@ -103,7 +112,7 @@ class Tree {
return lift[0][u];
}
- int dist(int u, int v, int anc = -1) {
+ int dist(int u, int v, int anc = -1) const {
if (anc == -1) { anc = lca(u, v); }
return depth[u] + depth[v] - 2 * depth[anc];
}
@@ -159,15 +168,6 @@ class Tree {
}
}
- void dfs(int u, int p) {
- for (int v : adj[u]) {
- if (v == p) { continue; }
- dfs(v, u);
- diff[u][0] += diff[v][0] + diff[v][1];
- diff[u][1] += diff[v][1];
- }
- }
-
vector calculate_result() {
dfs(1, 0);
vector res(n + 1);
From c1a1f2f699e1a79b287bdd56765773677e5c2538 Mon Sep 17 00:00:00 2001
From: TheGamingMousse <68484800+TheGamingMousse@users.noreply.github.com>
Date: Sat, 4 May 2024 16:49:49 -0700
Subject: [PATCH 18/23] added lil comment
---
solutions/platinum/bts-hotcold.mdx | 2 ++
1 file changed, 2 insertions(+)
diff --git a/solutions/platinum/bts-hotcold.mdx b/solutions/platinum/bts-hotcold.mdx
index 674bd3022e..d27956bfab 100644
--- a/solutions/platinum/bts-hotcold.mdx
+++ b/solutions/platinum/bts-hotcold.mdx
@@ -103,6 +103,8 @@ class Tree {
return lift[0][u];
}
+ // calculates distance from u to anc, and then to v
+ // if no ancestor is provided, anc = lca(u, v)
int dist(int u, int v, int anc = -1) {
if (anc == -1) { anc = lca(u, v); }
return depth[u] + depth[v] - 2 * depth[anc];
From 4e9fbcbd7f309f96c6ceb1796200d6c4a745414c Mon Sep 17 00:00:00 2001
From: TheGamingMousse <68484800+TheGamingMousse@users.noreply.github.com>
Date: Sat, 4 May 2024 16:51:19 -0700
Subject: [PATCH 19/23] added comment
---
solutions/platinum/bts-hotcold.mdx | 2 ++
1 file changed, 2 insertions(+)
diff --git a/solutions/platinum/bts-hotcold.mdx b/solutions/platinum/bts-hotcold.mdx
index 674bd3022e..42f78baf4e 100644
--- a/solutions/platinum/bts-hotcold.mdx
+++ b/solutions/platinum/bts-hotcold.mdx
@@ -103,6 +103,8 @@ class Tree {
return lift[0][u];
}
+ // calculates distance from u to anc, and then anc to v
+ // if anc is not provided, anc is set to lca(u, v)
int dist(int u, int v, int anc = -1) {
if (anc == -1) { anc = lca(u, v); }
return depth[u] + depth[v] - 2 * depth[anc];
From 3aeacd5746416603a56a4351ce0286b9bfe5ab7d Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Sat, 4 May 2024 23:54:13 +0000
Subject: [PATCH 20/23] [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---
solutions/platinum/bts-hotcold.mdx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/solutions/platinum/bts-hotcold.mdx b/solutions/platinum/bts-hotcold.mdx
index 42f78baf4e..37c5232d7b 100644
--- a/solutions/platinum/bts-hotcold.mdx
+++ b/solutions/platinum/bts-hotcold.mdx
@@ -68,7 +68,7 @@ class Tree {
vector tout;
int timer = 0;
- void tour(int u, int p) {
+ void tour(int u, int p) {
tin[u] = timer++;
lift[0][u] = p;
depth[u] = depth[p] + 1;
@@ -103,7 +103,7 @@ class Tree {
return lift[0][u];
}
- // calculates distance from u to anc, and then anc to v
+ // calculates distance from u to anc, and then anc to v
// if anc is not provided, anc is set to lca(u, v)
int dist(int u, int v, int anc = -1) {
if (anc == -1) { anc = lca(u, v); }
From 9277b339971451240885712f92d7d284bbf1400c Mon Sep 17 00:00:00 2001
From: TheGamingMousse <68484800+TheGamingMousse@users.noreply.github.com>
Date: Sat, 4 May 2024 17:19:34 -0700
Subject: [PATCH 21/23] fixed my oopsie lol
---
solutions/platinum/bts-hotcold.mdx | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/solutions/platinum/bts-hotcold.mdx b/solutions/platinum/bts-hotcold.mdx
index 42f78baf4e..37952395e9 100644
--- a/solutions/platinum/bts-hotcold.mdx
+++ b/solutions/platinum/bts-hotcold.mdx
@@ -68,7 +68,7 @@ class Tree {
vector tout;
int timer = 0;
- void tour(int u, int p) {
+ void tour(int u, int p) {
tin[u] = timer++;
lift[0][u] = p;
depth[u] = depth[p] + 1;
@@ -81,6 +81,15 @@ class Tree {
tout[u] = timer - 1;
}
+ void dfs(int u, int p) {
+ for (int v : adj[u]) {
+ if (v == p) { continue; }
+ dfs(v, u);
+ diff[u][0] += diff[v][0] + diff[v][1];
+ diff[u][1] += diff[v][1];
+ }
+ }
+
public:
Tree(int n, vector> &adj)
: n(n), log2dist((int)log2(n) + 1), adj(adj),
@@ -90,11 +99,11 @@ class Tree {
tour(1, 0);
}
- bool is_ancestor(int u, int v) {
+ bool is_ancestor(int u, int v) const {
return tin[u] <= tin[v] && tout[v] <= tout[u];
}
- int lca(int u, int v) {
+ int lca(int u, int v) const {
if (is_ancestor(u, v)) { return u; }
if (is_ancestor(v, u)) { return v; }
for (int i = log2dist - 1; i >= 0; i--) {
@@ -105,7 +114,7 @@ class Tree {
// calculates distance from u to anc, and then anc to v
// if anc is not provided, anc is set to lca(u, v)
- int dist(int u, int v, int anc = -1) {
+ int dist(int u, int v, int anc = -1) const {
if (anc == -1) { anc = lca(u, v); }
return depth[u] + depth[v] - 2 * depth[anc];
}
@@ -161,15 +170,6 @@ class Tree {
}
}
- void dfs(int u, int p) {
- for (int v : adj[u]) {
- if (v == p) { continue; }
- dfs(v, u);
- diff[u][0] += diff[v][0] + diff[v][1];
- diff[u][1] += diff[v][1];
- }
- }
-
vector calculate_result() {
dfs(1, 0);
vector res(n + 1);
From 0710999731749e7db39d41c9b90b804217764a7f Mon Sep 17 00:00:00 2001
From: SansPapyrus683 <55369003+SansPapyrus683@users.noreply.github.com>
Date: Sat, 4 May 2024 17:33:14 -0700
Subject: [PATCH 22/23] Update bts-hotcold.mdx
---
solutions/platinum/bts-hotcold.mdx | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/solutions/platinum/bts-hotcold.mdx b/solutions/platinum/bts-hotcold.mdx
index 434586a341..b161c66a14 100644
--- a/solutions/platinum/bts-hotcold.mdx
+++ b/solutions/platinum/bts-hotcold.mdx
@@ -112,8 +112,10 @@ class Tree {
return lift[0][u];
}
- // calculates distance from u to anc, and then anc to v
- // if anc is not provided, anc is set to lca(u, v)
+ /**
+ * @return the distance from u to anc, and then anc to v
+ * if anc is not provided, it's set to lca(u, v)
+ */
int dist(int u, int v, int anc = -1) const {
if (anc == -1) { anc = lca(u, v); }
return depth[u] + depth[v] - 2 * depth[anc];
From deaad3a2d90a1e85561a75481331df6c11aca14e Mon Sep 17 00:00:00 2001
From: SansPapyrus683 <55369003+SansPapyrus683@users.noreply.github.com>
Date: Sat, 4 May 2024 17:33:39 -0700
Subject: [PATCH 23/23] Update bts-hotcold.mdx
---
solutions/platinum/bts-hotcold.mdx | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/solutions/platinum/bts-hotcold.mdx b/solutions/platinum/bts-hotcold.mdx
index b161c66a14..4b7bfbab0f 100644
--- a/solutions/platinum/bts-hotcold.mdx
+++ b/solutions/platinum/bts-hotcold.mdx
@@ -81,6 +81,17 @@ class Tree {
tout[u] = timer - 1;
}
+ void update(int u, int v, int initial, int change) {
+ diff[u][0] += initial;
+ diff[u][1] += change;
+ if (change > 0) {
+ diff[v][0] -= initial + (depth[u] - depth[v]);
+ } else {
+ diff[v][0] -= initial - (depth[u] - depth[v]);
+ }
+ diff[v][1] -= change;
+ }
+
void dfs(int u, int p) {
for (int v : adj[u]) {
if (v == p) { continue; }
@@ -121,17 +132,6 @@ class Tree {
return depth[u] + depth[v] - 2 * depth[anc];
}
- void update(int u, int v, int initial, int change) {
- diff[u][0] += initial;
- diff[u][1] += change;
- if (change > 0) {
- diff[v][0] -= initial + (depth[u] - depth[v]);
- } else {
- diff[v][0] -= initial - (depth[u] - depth[v]);
- }
- diff[v][1] -= change;
- }
-
void query(int a, int b, int t) {
int anc = lca(a, b);
if (anc == t || !is_ancestor(anc, t)) {