From 28d701cc11a510f1d5102490d93eb681e1ac31a5 Mon Sep 17 00:00:00 2001 From: florian Date: Thu, 29 Aug 2024 17:01:39 +0200 Subject: shorter rerooting (tested on https://codeforces.com/gym/532576/submission/278656979) --- content/graph/reroot.cpp | 99 ++++++++++++++++++++---------------------------- 1 file changed, 42 insertions(+), 57 deletions(-) (limited to 'content') diff --git a/content/graph/reroot.cpp b/content/graph/reroot.cpp index 4c6a748..59fea94 100644 --- a/content/graph/reroot.cpp +++ b/content/graph/reroot.cpp @@ -1,62 +1,47 @@ -// Usual Tree DP can be broken down in 4 steps: -// - Initialize dp[v] = identity -// - Iterate over all children w and take a value for w -// by looking at dp[w] and possibly the edge label of v -> w -// - combine the values of those children -// usually this operation should be commutative and associative -// - finalize the dp[v] after iterating over all children +// input: undirected (un)weighted tree as +// adjacency list containing pairs +// (To remove weights, remove every "w" and fix errors) +// output[r] = dp[r], where dp[v] := +// fin(Sum_{child c of v, regarding root r} from_child( dp[c] )) struct Reroot { - using T = ll; + using D = todo; // dp value + using A = todo (often D); // value from a vertex's child(ren) + // (A,agg,e) commutative monoid - // identity element - T E() {} - // x: dp value of child - // e: index of edge going to child - T takeChild(T x, int e) {} - T comb(T x, T y) {} - // called after combining all dp values of children - T fin(T x, int v) {} + A e = todo; + A from_child(z v, z c, auto w, D dp_c) { todo } + static A agg(A a, A b) { todo } + D fin(z v, A chils_agg) { todo } - vector>> g; - vector ord, pae; - vector dp; + vector dp; - T dfs(int v) { - ord.push_back(v); - for (auto [w, e] : g[v]) { - g[w].erase(find(all(g[w]), pair(v, e^1))); - pae[w] = e^1; - dp[v] = comb(dp[v], takeChild(dfs(w), e)); - } - return dp[v] = fin(dp[v], v); - } + D dfs0(z v, z p, auto& g) { + A ca = e; + for (auto [c, w] : g[v]) if(c-p) { + ca = agg(ca, from_child(v, c, w, dfs0(c, v, g))); + } + return dp[v] = fin(v, ca); + } + void dfs1(z v, z p, auto& g) { + vector ps = {e}; + for (auto [c, w] : g[v]) { + ps.push_back(from_child(v, c, w, dp[c])); + } + auto ss = ps; + exclusive_scan(ps.begin(), ps.end(), ps.begin(), e, agg); + exclusive_scan(ss.rbegin(),ss.rend(),ss.rbegin(),e, agg); + z i = 0; + for (auto [c, w] : g[v]) if(++i, c-p) { + dp[v] = fin(v, agg(ss[i], ps[i])); + dfs1(c, v, g); + } + dp[v] = fin(v, ss[0]); + } - vector solve(int n, vector> edges) { - g.resize(n); - for (int i = 0; i < n-1; i++) { - g[edges[i].first].emplace_back(edges[i].second, 2*i); - g[edges[i].second].emplace_back(edges[i].first, 2*i+1); - } - pae.assign(n, -1); - dp.assign(n, E()); - dfs(0); - vector updp(n, E()), res(n, E()); - for (int v : ord) { - vector pref(sz(g[v])+1), suff(sz(g[v])+1); - if (v != 0) pref[0] = takeChild(updp[v], pae[v]); - for (int i = 0; i < sz(g[v]); i++){ - auto [u, w] = g[v][i]; - pref[i+1] = suff[i] = takeChild(dp[u], w); - pref[i+1] = comb(pref[i], pref[i+1]); - } - for (int i = sz(g[v])-1; i >= 0; i--) { - suff[i] = comb(suff[i], suff[i+1]); - } - for (int i = 0; i < sz(g[v]); i++) { - updp[g[v][i].first] = fin(comb(pref[i], suff[i+1]), v); - } - res[v] = fin(pref.back(), v); - } - return res; - } -}; + auto solve(auto g) { + dp.resize(sz(g)); + dfs0(0, 0, g); + dfs1(0, 0, g); + return dp; + } +}; \ No newline at end of file -- cgit v1.2.3 From 3328e0fd09ce1cca46ade4a492edff92a3edb8ac Mon Sep 17 00:00:00 2001 From: florian Date: Thu, 29 Aug 2024 17:25:34 +0200 Subject: code style --- content/graph/reroot.cpp | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) (limited to 'content') diff --git a/content/graph/reroot.cpp b/content/graph/reroot.cpp index 59fea94..6c9551e 100644 --- a/content/graph/reroot.cpp +++ b/content/graph/reroot.cpp @@ -1,47 +1,51 @@ -// input: undirected (un)weighted tree as -// adjacency list containing pairs -// (To remove weights, remove every "w" and fix errors) // output[r] = dp[r], where dp[v] := -// fin(Sum_{child c of v, regarding root r} from_child( dp[c] )) +// fin(Sum_{child c of v, regarding root r} fromChild( dp[c] )) + +// To remove weights, remove every "w" and "W" and fix errors struct Reroot { - using D = todo; // dp value - using A = todo (often D); // value from a vertex's child(ren) + using D = /todo/; // dp value + using A = /todo/ (often D); // value from a vertex's child(ren) // (A,agg,e) commutative monoid - A e = todo; - A from_child(z v, z c, auto w, D dp_c) { todo } - static A agg(A a, A b) { todo } - D fin(z v, A chils_agg) { todo } + A e = /todo/; + A fromChild(int v, int c, auto w, D dp_c) { /todo/ } + static A agg(A a, A b) { /todo/ } + D fin(int v, A chilsAgg) { /todo/ } vector dp; - D dfs0(z v, z p, auto& g) { + D dfs0(auto& g, int v, int from = -1) { A ca = e; - for (auto [c, w] : g[v]) if(c-p) { - ca = agg(ca, from_child(v, c, w, dfs0(c, v, g))); + for (auto [c, w] : g[v]) { + if (c == from) continue; + ca = agg(ca, fromChild(v, c, w, dfs0(c, v, g))); } return dp[v] = fin(v, ca); } - void dfs1(z v, z p, auto& g) { + + void dfs1(auto& g, int v, int from = -1) { vector ps = {e}; for (auto [c, w] : g[v]) { - ps.push_back(from_child(v, c, w, dp[c])); + ps.push_back(fromChild(v, c, w, dp[c])); } auto ss = ps; exclusive_scan(ps.begin(), ps.end(), ps.begin(), e, agg); exclusive_scan(ss.rbegin(),ss.rend(),ss.rbegin(),e, agg); - z i = 0; - for (auto [c, w] : g[v]) if(++i, c-p) { + int i = 0; + for (auto [c, w] : g[v]) { + ++i; + if (c == from) continue; dp[v] = fin(v, agg(ss[i], ps[i])); dfs1(c, v, g); } dp[v] = fin(v, ss[0]); } - auto solve(auto g) { + template + auto solve(vector>> g) { dp.resize(sz(g)); - dfs0(0, 0, g); - dfs1(0, 0, g); + dfs0(g, 0); + dfs1(g, 0); return dp; } }; \ No newline at end of file -- cgit v1.2.3 From 4d8f28ec2dceff1eed72c86463235407dc23d42b Mon Sep 17 00:00:00 2001 From: florian Date: Thu, 29 Aug 2024 17:34:18 +0200 Subject: be --- content/graph/reroot.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'content') diff --git a/content/graph/reroot.cpp b/content/graph/reroot.cpp index 6c9551e..f908d52 100644 --- a/content/graph/reroot.cpp +++ b/content/graph/reroot.cpp @@ -29,8 +29,8 @@ struct Reroot { ps.push_back(fromChild(v, c, w, dp[c])); } auto ss = ps; - exclusive_scan(ps.begin(), ps.end(), ps.begin(), e, agg); - exclusive_scan(ss.rbegin(),ss.rend(),ss.rbegin(),e, agg); + exclusive_scan(be(ps), ps.begin(), e, agg); + exclusive_scan(ss.rbegin(), ss.rend(), ss.rbegin(), e, agg); int i = 0; for (auto [c, w] : g[v]) { ++i; -- cgit v1.2.3 From 8ba51e146ad9805f3e2c7e1698a9e604f1dd2379 Mon Sep 17 00:00:00 2001 From: florian Date: Thu, 29 Aug 2024 17:39:06 +0200 Subject: todos --- content/graph/reroot.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'content') diff --git a/content/graph/reroot.cpp b/content/graph/reroot.cpp index f908d52..b3571f1 100644 --- a/content/graph/reroot.cpp +++ b/content/graph/reroot.cpp @@ -3,14 +3,14 @@ // To remove weights, remove every "w" and "W" and fix errors struct Reroot { - using D = /todo/; // dp value - using A = /todo/ (often D); // value from a vertex's child(ren) - // (A,agg,e) commutative monoid + using D = /*todo*/; // dp value + using A = /*todo(often D)*/; //value from a vertex's child(ren) + //(A,agg,e) commutative monoid - A e = /todo/; - A fromChild(int v, int c, auto w, D dp_c) { /todo/ } - static A agg(A a, A b) { /todo/ } - D fin(int v, A chilsAgg) { /todo/ } + A e = /*todo*/; + A fromChild(int v, int c, auto w, D dp_c) { /*todo*/ } + static A agg(A a, A b) { /*todo*/ } + D fin(int v, A chilsAgg) { /*todo*/ } vector dp; -- cgit v1.2.3 From 96f899b7350fe05232d906478e9ca9d26f558969 Mon Sep 17 00:00:00 2001 From: Yidi Date: Mon, 2 Sep 2024 16:35:15 +0200 Subject: fix style --- content/graph/reroot.cpp | 85 +++++++++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 44 deletions(-) (limited to 'content') diff --git a/content/graph/reroot.cpp b/content/graph/reroot.cpp index b3571f1..cd63b3d 100644 --- a/content/graph/reroot.cpp +++ b/content/graph/reroot.cpp @@ -1,51 +1,48 @@ -// output[r] = dp[r], where dp[v] := -// fin(Sum_{child c of v, regarding root r} fromChild( dp[c] )) +using W = ll; // edge weight type +vector>> adj; -// To remove weights, remove every "w" and "W" and fix errors struct Reroot { - using D = /*todo*/; // dp value - using A = /*todo(often D)*/; //value from a vertex's child(ren) - //(A,agg,e) commutative monoid + using T = ll; // dp type - A e = /*todo*/; - A fromChild(int v, int c, auto w, D dp_c) { /*todo*/ } - static A agg(A a, A b) { /*todo*/ } - D fin(int v, A chilsAgg) { /*todo*/ } + static constexpr T E = 0; // neutral element + T takeChild(int v, int c, W w, T x) {} // move child along edge + static T comb(T x, T y) {} + T fin(int v, T x) {} // add v to own dp value x - vector dp; + vector dp; - D dfs0(auto& g, int v, int from = -1) { - A ca = e; - for (auto [c, w] : g[v]) { - if (c == from) continue; - ca = agg(ca, fromChild(v, c, w, dfs0(c, v, g))); - } - return dp[v] = fin(v, ca); - } + T dfs0(int v, int from = -1) { + T val = E; + for (auto& [u, w] : adj[v]) { + if (u == from) continue; + val = comb(val, takeChild(v, u, w, dfs0(u, v))); + } + return dp[v] = fin(v, val); + } - void dfs1(auto& g, int v, int from = -1) { - vector ps = {e}; - for (auto [c, w] : g[v]) { - ps.push_back(fromChild(v, c, w, dp[c])); - } - auto ss = ps; - exclusive_scan(be(ps), ps.begin(), e, agg); - exclusive_scan(ss.rbegin(), ss.rend(), ss.rbegin(), e, agg); - int i = 0; - for (auto [c, w] : g[v]) { - ++i; - if (c == from) continue; - dp[v] = fin(v, agg(ss[i], ps[i])); - dfs1(c, v, g); - } - dp[v] = fin(v, ss[0]); - } + void dfs1(int v, int from = -1) { + vector pref = {E}; + for (auto [u, w] : adj[v]) { + pref.push_back(takeChild(v, u, w, dp[u])); + } + auto suf = pref; + partial_sum(all(pref), pref.begin(), comb); + exclusive_scan(suf.rbegin(), suf.rend(), + suf.rbegin(), E, comb); - template - auto solve(vector>> g) { - dp.resize(sz(g)); - dfs0(g, 0); - dfs1(g, 0); - return dp; - } -}; \ No newline at end of file + for (int i = 0; i < sz(adj[v]); i++) { + auto [u, w] = adj[v][i]; + if (u == from) continue; + dp[v] = fin(v, comb(pref[i], suf[i + 1])); + dfs1(u, v); + } + dp[v] = fin(v, suf[0]); + } + + auto solve() { + dp.assign(sz(adj), E); + dfs0(0); + dfs1(0); + return dp; + } +}; -- cgit v1.2.3 From 24db7e1f387b458e8a48c3b773860e32f897017c Mon Sep 17 00:00:00 2001 From: Yidi Date: Mon, 2 Sep 2024 16:54:30 +0200 Subject: remove inconsistent reference --- content/graph/reroot.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'content') diff --git a/content/graph/reroot.cpp b/content/graph/reroot.cpp index cd63b3d..379c839 100644 --- a/content/graph/reroot.cpp +++ b/content/graph/reroot.cpp @@ -13,7 +13,7 @@ struct Reroot { T dfs0(int v, int from = -1) { T val = E; - for (auto& [u, w] : adj[v]) { + for (auto [u, w] : adj[v]) { if (u == from) continue; val = comb(val, takeChild(v, u, w, dfs0(u, v))); } -- cgit v1.2.3 From 943d96c5f7cde38e5ec02b1cdb29bb7c8766574c Mon Sep 17 00:00:00 2001 From: f1or1an <110727007+f1or1an@users.noreply.github.com> Date: Tue, 3 Sep 2024 22:15:06 +0200 Subject: remove static constexpr --- content/graph/reroot.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'content') diff --git a/content/graph/reroot.cpp b/content/graph/reroot.cpp index 379c839..3ed19d0 100644 --- a/content/graph/reroot.cpp +++ b/content/graph/reroot.cpp @@ -4,7 +4,7 @@ vector>> adj; struct Reroot { using T = ll; // dp type - static constexpr T E = 0; // neutral element + T E = 0; // neutral element T takeChild(int v, int c, W w, T x) {} // move child along edge static T comb(T x, T y) {} T fin(int v, T x) {} // add v to own dp value x -- cgit v1.2.3 From 568329cab9a64d8059fe58142d35c43dfc08355e Mon Sep 17 00:00:00 2001 From: f1or1an <110727007+f1or1an@users.noreply.github.com> Date: Fri, 6 Sep 2024 00:20:38 +0200 Subject: Update content/graph/reroot.cpp --- content/graph/reroot.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'content') diff --git a/content/graph/reroot.cpp b/content/graph/reroot.cpp index 3ed19d0..379c839 100644 --- a/content/graph/reroot.cpp +++ b/content/graph/reroot.cpp @@ -4,7 +4,7 @@ vector>> adj; struct Reroot { using T = ll; // dp type - T E = 0; // neutral element + static constexpr T E = 0; // neutral element T takeChild(int v, int c, W w, T x) {} // move child along edge static T comb(T x, T y) {} T fin(int v, T x) {} // add v to own dp value x -- cgit v1.2.3