cpinitiative / usaco-guide

A free collection of curated, high-quality resources to take you from Bronze to Platinum and beyond.
https://usaco.guide
Other
1.62k stars 495 forks source link

Contact Form Submission - Suggestion (Gold - DP on Trees - Solving For All Roots) #4863

Open maggieliu05 opened 1 month ago

maggieliu05 commented 1 month ago

Someone submitted the contact form!

URL: https://usaco.guide/gold/all-roots?lang=cpp Module: Gold - DP on Trees - Solving For All Roots Topic: Suggestion Message: Worth mentioning rerooting templates that allow implementing such problems more quickly and reliably in linear time. Example: https://codeforces.com/blog/entry/124286 (though this is NlogN rather than N)

bqi343 commented 1 month ago

Example: solving Tree Distances I with a template modified from the blog to run in linear time.


...

namespace reroot {

auto rerooter = [](const auto &g, const auto &init_a, const auto &v_to_a,
                   const auto &a_to_v, const auto &add) {
    using Agg = decay_t<decltype(init_a())>;
    using Val = decay_t<decltype(a_to_v(init_a(), 0))>;
    int N = sz(g);
    vi par(N);
    V<Val> dp(N), dp_root(N);
    V<V<Val>> dp_down(N), dp_up(N);
    y_combinator([&](auto dfs_down, int x) -> void {
        Agg agg = init_a();
        F0R(e, sz(g[x])) {
            int y = g[x][e];
            if (y != par[x]) {
                par[y] = x;
                dfs_down(y);
                agg = add(agg, v_to_a(dp[y], x, e));
            }
        }
        dp[x] = a_to_v(agg, x);
    })(0);
    y_combinator([&](auto dfs_up, int x) -> void {
        dp[par[x]] = dp[x];
        V<Agg> pref_aggs{init_a()}, suf_aggs{init_a()};
        F0R(e, sz(g[x])) {
            int y = g[x][e];
            pref_aggs.pb(add(pref_aggs.bk, v_to_a(dp[y], x, e)));
        }
        R0F(e, sz(g[x])) {
            int y = g[x][e];
            suf_aggs.pb(add(suf_aggs.bk, v_to_a(dp[y], x, e)));
        }
        dp_root[x] = a_to_v(pref_aggs.bk, x);
        F0R(e, sz(g[x])) {
            int y = g[x][e];
            dp_down[x].pb(dp[y]);
            dp_up[x].pb(
                a_to_v(add(pref_aggs[e], suf_aggs[sz(g[x]) - 1 - e]), x));
            if (y != par[x]) {
                dp[y] = dp_up[x][e];
                dfs_up(y);
            }
        }
    })(0);
    return make_tuple(dp_root, dp_down, dp_up);
};

}

int main() {
    setIO();
    def(int, N);
    V<vi> g(N);
    rep(N - 1) {
        def(int, a, b);
        --a, --b;
        g[a].pb(b), g[b].pb(a);
    }
    struct Val {  // max depth for subtree including root
        int mx;
    };
    struct Agg {  // max depth for subtree excluding root
        int mx;
    };
    auto [dp_root, dp_down, dp_up] = reroot::rerooter(
        g,
        []() -> Agg {  // init empty subtree
            return {};
        },
        [](Val v, int x, int e) -> Agg {  // add edge to subtree
            return {v.mx};
        },
        [](Agg a, int x) -> Val {  // add root to subtree
            return {a.mx + 1};
        },
        [](Agg a, Agg b) -> Agg {  // merge subtrees
            return {max(a.mx, b.mx)};
        });
    vi ans;
    F0R(i, N) ans.pb(dp_root.at(i).mx - 1);
    ps(ans);
}