Algorithms

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

View on GitHub

:heavy_check_mark: tree/tree_diameter.hpp

Depends on

Verified with

Code

#ifndef TREE_DIAMETER_HPP
#define TREE_DIAMETER_HPP

#include "graph/csr_graph.hpp"
#include <algorithm>
#include <cassert>
#include <vector>

// requires non-negative edge weights
// return (diameter, path)
// for an unweighted tree, centers are path[d / 2] and path[(d + 1) / 2]
template <typename EdgeWeight> auto tree_diameter(const CSRGraph<EdgeWeight> &g) {
    assert(0 < g.size());
    auto n = int(g.size());
    std::vector<int> parent(n, -1);
    std::vector<EdgeWeight> depth(n);
    auto dfs = [&](int x) {
        std::vector<int> st;
        st.push_back(x);
        parent[x] = -1;
        depth[x] = 0;
        while (!st.empty()) {
            auto u = st.back();
            st.pop_back();
            for (const auto &e : g[u]) {
                if (e.v != parent[u]) {
                    st.push_back(e.v);
                    parent[e.v] = u;
                    depth[e.v] = depth[u] + e.w;
                }
            }
        }
        auto it = std::ranges::max_element(depth);
        auto r = int(it - depth.begin());
        return std::pair(r, *it);
    };
    auto x = dfs(0).first;
    auto [y, d] = dfs(x);
    std::vector<int> path;
    for (auto u = y; ~u; u = parent[u]) {
        path.push_back(u);
    }
    return std::pair(d, path);
}

#endif // TREE_DIAMETER_HPP
#line 1 "tree/tree_diameter.hpp"



#line 1 "graph/csr_graph.hpp"



#include <cassert>
#include <ranges>
#include <vector>

template <typename EdgeWeight = int> struct CSRGraph {
    struct Edge {
        int u;
        int v;
        EdgeWeight w;
        int i;
    };
    CSRGraph(int n) : n_(n) {}
    void add_edge(int u, int v, EdgeWeight w = 1) {
        assert(!built_);
        assert(0 <= u && u < n_ && 0 <= v && v < n_);
        auto i = int(edges_.size());
        edges_.push_back({u, v, w, i});
    }
    void build_undirected() {
        assert(!built_);
        start_.assign(n_ + 1, 0);
        csr_.resize(2 * edges_.size());
        for (const auto &e : edges_) {
            ++start_[e.u + 1];
            ++start_[e.v + 1];
        }
        for (int i = 0; i < n_; ++i) {
            start_[i + 1] += start_[i];
        }
        auto pos = start_;
        for (const auto &e : edges_) {
            csr_[pos[e.u]++] = {e.u, e.v, e.w, e.i};
            csr_[pos[e.v]++] = {e.v, e.u, e.w, e.i};
        }
        built_ = true;
    }
    void build_directed() {
        assert(!built_);
        start_.assign(n_ + 1, 0);
        csr_.resize(edges_.size());
        for (const auto &e : edges_) {
            ++start_[e.u + 1];
        }
        for (int i = 0; i < n_; ++i) {
            start_[i + 1] += start_[i];
        }
        auto pos = start_;
        for (const auto &e : edges_) {
            csr_[pos[e.u]++] = e;
        }
        built_ = true;
    }
    auto operator[](int u) const {
        assert(built_);
        assert(0 <= u && u < n_);
        return std::ranges::subrange(csr_.begin() + start_[u], csr_.begin() + start_[u + 1]);
    }
    int size() const { return n_; }

private:
    int n_;
    bool built_ = false;
    std::vector<Edge> edges_;
    std::vector<Edge> csr_;
    std::vector<int> start_;
};


#line 5 "tree/tree_diameter.hpp"
#include <algorithm>
#line 8 "tree/tree_diameter.hpp"

// requires non-negative edge weights
// return (diameter, path)
// for an unweighted tree, centers are path[d / 2] and path[(d + 1) / 2]
template <typename EdgeWeight> auto tree_diameter(const CSRGraph<EdgeWeight> &g) {
    assert(0 < g.size());
    auto n = int(g.size());
    std::vector<int> parent(n, -1);
    std::vector<EdgeWeight> depth(n);
    auto dfs = [&](int x) {
        std::vector<int> st;
        st.push_back(x);
        parent[x] = -1;
        depth[x] = 0;
        while (!st.empty()) {
            auto u = st.back();
            st.pop_back();
            for (const auto &e : g[u]) {
                if (e.v != parent[u]) {
                    st.push_back(e.v);
                    parent[e.v] = u;
                    depth[e.v] = depth[u] + e.w;
                }
            }
        }
        auto it = std::ranges::max_element(depth);
        auto r = int(it - depth.begin());
        return std::pair(r, *it);
    };
    auto x = dfs(0).first;
    auto [y, d] = dfs(x);
    std::vector<int> path;
    for (auto u = y; ~u; u = parent[u]) {
        path.push_back(u);
    }
    return std::pair(d, path);
}
Back to top page