cplib-cpp

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub hitonanode/cplib-cpp

:heavy_check_mark: tree/test/lca.yuki898.test.cpp

Depends on

Code

#include "../lowest_common_ancestor.hpp"
#include <iostream>
#define PROBLEM "https://yukicoder.me/problems/no/898"
using namespace std;

int main() {
    cin.tie(nullptr), ios::sync_with_stdio(false);

    int N;
    cin >> N;
    UndirectedWeightedTree<long long> g(N);
    for (int i = 1; i <= N - 1; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        g.add_edge(u, v, w);
    }
    g.fix_root(0);

    int Q;
    cin >> Q;

    while (Q--) {
        int x, y, z;
        cin >> x >> y >> z;
        int xy = g.lowest_common_ancestor(x, y);
        int xyz = g.lowest_common_ancestor(xy, z);
        if (xy != xyz) {
            cout << g.path_length(xy, z) + g.path_length(x, y) << '\n';
        } else {
            int v = g.lowest_common_ancestor(x, z) + g.lowest_common_ancestor(y, z) - xy;
            cout << g.path_length(x, y) + g.path_length(z, v) << '\n';
        }
    }
}
#line 2 "tree/lowest_common_ancestor.hpp"
#include <utility>
#include <vector>

// CUT begin
// lowest common ancestor (LCA) for undirected weighted tree
template <typename T> struct UndirectedWeightedTree {
    int INVALID = -1;
    int V, lgV;
    int E;
    int root;
    std::vector<std::vector<std::pair<int, int>>> adj; // (nxt_vertex, edge_id)
    // vector<pint> edge; // edges[edge_id] = (vertex_id, vertex_id)
    std::vector<T> weight;     // w[edge_id]
    std::vector<int> par;      // parent_vertex_id[vertex_id]
    std::vector<int> depth;    // depth_from_root[vertex_id]
    std::vector<T> acc_weight; // w_sum_from_root[vertex_id]

    void _fix_root_dfs(int now, int prv, int prv_edge_id) {
        par[now] = prv;
        if (prv_edge_id != INVALID) acc_weight[now] = acc_weight[prv] + weight[prv_edge_id];
        for (auto nxt : adj[now])
            if (nxt.first != prv) {
                depth[nxt.first] = depth[now] + 1;
                _fix_root_dfs(nxt.first, now, nxt.second);
            }
    }

    UndirectedWeightedTree() = default;
    UndirectedWeightedTree(int N) : V(N), E(0), adj(N) {
        lgV = 1;
        while (1 << lgV < V) lgV++;
    }

    void add_edge(int u, int v, T w) {
        adj[u].emplace_back(v, E);
        adj[v].emplace_back(u, E);
        // edge.emplace_back(u, v);
        weight.emplace_back(w);
        E++;
    }

    std::vector<std::vector<int>> doubling;
    void _doubling_precalc() {
        doubling.assign(lgV, std::vector<int>(V));
        doubling[0] = par;
        for (int d = 0; d < lgV - 1; d++)
            for (int i = 0; i < V; i++) {
                if (doubling[d][i] == INVALID)
                    doubling[d + 1][i] = INVALID;
                else
                    doubling[d + 1][i] = doubling[d][doubling[d][i]];
            }
    }

    void fix_root(int r) {
        root = r;
        par.resize(V);
        depth.resize(V);
        depth[r] = 0;
        acc_weight.resize(V);
        acc_weight[r] = 0;
        _fix_root_dfs(root, INVALID, INVALID);
        _doubling_precalc();
    }

    int kth_parent(int x, int k) const {
        if (depth[x] < k) return INVALID;
        for (int d = 0; d < lgV; d++) {
            if (x == INVALID) return INVALID;
            if (k & (1 << d)) x = doubling[d][x];
        }
        return x;
    }

    int lowest_common_ancestor(int u, int v) const {
        if (depth[u] > depth[v]) std::swap(u, v);

        v = kth_parent(v, depth[v] - depth[u]);
        if (u == v) return u;
        for (int d = lgV - 1; d >= 0; d--) {
            if (doubling[d][u] != doubling[d][v]) u = doubling[d][u], v = doubling[d][v];
        }
        return par[u];
    }

    T path_length(int u, int v) const {
        // Not distance, but the sum of weights
        int r = lowest_common_ancestor(u, v);
        return (acc_weight[u] - acc_weight[r]) + (acc_weight[v] - acc_weight[r]);
    }

    int s_to_t_by_k_steps(int s, int t, int k) const {
        int l = lowest_common_ancestor(s, t);
        int dsl = depth[s] - depth[l], dtl = depth[t] - depth[l];
        if (k > dsl + dtl) {
            return INVALID;
        } else if (k < dsl) {
            return kth_parent(s, k);
        } else if (k == dsl) {
            return l;
        } else {
            return kth_parent(t, dsl + dtl - k);
        }
    }
};
#line 2 "tree/test/lca.yuki898.test.cpp"
#include <iostream>
#define PROBLEM "https://yukicoder.me/problems/no/898"
using namespace std;

int main() {
    cin.tie(nullptr), ios::sync_with_stdio(false);

    int N;
    cin >> N;
    UndirectedWeightedTree<long long> g(N);
    for (int i = 1; i <= N - 1; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        g.add_edge(u, v, w);
    }
    g.fix_root(0);

    int Q;
    cin >> Q;

    while (Q--) {
        int x, y, z;
        cin >> x >> y >> z;
        int xy = g.lowest_common_ancestor(x, y);
        int xyz = g.lowest_common_ancestor(xy, z);
        if (xy != xyz) {
            cout << g.path_length(xy, z) + g.path_length(x, y) << '\n';
        } else {
            int v = g.lowest_common_ancestor(x, z) + g.lowest_common_ancestor(y, z) - xy;
            cout << g.path_length(x, y) + g.path_length(z, v) << '\n';
        }
    }
}
Back to top page