Thanks to visit codestin.com
Credit goes to hitonanode.github.io

cplib-cpp

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

View the Project on GitHub hitonanode/cplib-cpp

:heavy_check_mark: graph/test/directed_mst.aoj.test.cpp

Depends on

Code

#include "../directed_mst.hpp"
#include <iostream>
using namespace std;
#define PROBLEM "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_2_B"

int main() {
    int N, M, S;
    cin >> N >> M >> S;
    std::vector<std::tuple<int, int, long long>> edges;
    while (M--) {
        int a, b, c;
        cin >> a >> b >> c;
        edges.emplace_back(a, b, c);
    }
    MinimumSpanningArborescence<long long> msa(N, edges, S);
    cout << msa.ret << '\n';
}
#line 2 "graph/directed_mst.hpp"
#include <cassert>
#include <numeric>
#include <tuple>
#include <utility>
#include <vector>

// CUT begin
// Minimum spanning tree for directed graph (spanning arborescence)
//
// Complexity: O(nm) (Chu-Liu/Edmonds' algorithm)
// Verify: https://judge.yosupo.jp/problem/directedmst
// Reference:
// [1] R. E. Tarjan, "Finding optimum branchings," Networks 7.1 (1977): 25-35.
// - https://joisino.hatenablog.com/entry/2017/01/11/230141
template <typename Weight = long long> struct MinimumSpanningArborescence {
    struct noswap_unionfind {
        std::vector<int> par;
        void initialize(int N) {
            par.resize(N);
            std::iota(par.begin(), par.end(), 0);
        }
        int find(int x) { return (par[x] == x) ? x : par[x] = find(par[x]); }
        bool unite(int child, int parent) {
            child = find(child), parent = find(parent);
            if (child == parent) return false;
            par[child] = parent;
            return true;
        }
        bool same(int x, int y) { return find(x) == find(y); }
    } uf;

    struct skew_heap {
        struct node;
        static std::vector<node> data;
        static unsigned len;
        using ptr = int;
        struct node {
        private:
            Weight add, val;
            int id;

        public:
            ptr l, r;
            node(Weight val, int id_) : add(0), val(val), id(id_), l(-1), r(-1) {}
            node() = default;
            Weight weight() const noexcept { return add + val; }
            int getid() const noexcept { return id; }
            void push() {
                if (l != -1) data[l].add += this->add;
                if (r != -1) data[r].add += this->add;
                this->val += this->add;
                this->add = 0;
            }
            void apply(Weight w) { this->add += w; }
        };

        ptr _meld(ptr a, ptr b) {
            if (a == -1) return b;
            if (b == -1) return a;
            if (data[b].weight() < data[a].weight()) std::swap(a, b);
            data[a].push();
            data[a].r = _meld(data[a].r, b);
            std::swap(data[a].l, data[a].r);
            return a;
        }

        ptr root;
        int sz;

        ptr _new_node(Weight value, int id_) {
            if (len >= data.size()) data.resize(std::max<int>(1024, data.size() * 2));
            data[len] = node(value, id_);
            return len++;
        }

    public:
        skew_heap() : root(-1), sz(0) {}
        void push(Weight value, int id_) {
            root = _meld(_new_node(value, id_), root);
            sz++;
        }
        void merge(skew_heap &heap) {
            this->root = _meld(this->root, heap.root);
            if (heap.root != -1) this->sz += heap.sz;
            heap = skew_heap();
        }
        std::pair<Weight, int> top() const { return {data[root].weight(), data[root].getid()}; }
        void add_all(Weight w) {
            if (root != -1) data[root].apply(w);
        }
        void pop() {
            data[root].push();
            root = _meld(data[root].r, data[root].l);
        }
        int size() const { return sz; }
        bool empty() const { return sz == 0; }
    };

    Weight ret;
    MinimumSpanningArborescence(const int N,
                                const std::vector<std::tuple<int, int, Weight>> &edges, int r) {
        assert(r >= 0 and r < N);
        std::vector<short> used(N);
        std::vector<skew_heap> incoming_edges(N);

        ret = 0;
        std::vector<int> from(N, r);
        std::vector<Weight> from_cost(N, 0);
        std::vector<int> used_eids;
        uf.initialize(N);
        used[r] = 2;

        // std::vector<int> par(N, -1);
        int s, t;
        Weight w;
        for (int eid = 0; eid < int(edges.size()); eid++) {
            std::tie(s, t, w) = edges[eid];
            incoming_edges[t].push(w, eid);
        }

        for (int start = 0; start < N; start++) {
            if (used[start] != 0) continue;
            int cur = start;
            std::vector<int> processing;
            while (used[cur] != 2) {
                used[cur] = 1;
                processing.push_back(cur);
                if (incoming_edges[cur].empty()) {
                    // No solution
                    return;
                }

                int eid;
                Weight w;
                std::tie(w, eid) = incoming_edges[cur].top();
                from[cur] = uf.find(std::get<0>(edges[eid]));
                // par[cur] = std::get<0>(edges[eid]);
                // par[std::get<1>(edges[eid])] = std::get<0>(edges[eid]);
                from_cost[cur] = w;
                incoming_edges[cur].pop();
                if (from[cur] == cur) continue;

                ret += from_cost[cur];
                used_eids.push_back(eid);

                if (used[from[cur]] == 1) {
                    int p = cur;
                    do {
                        incoming_edges[p].add_all(-from_cost[p]);
                        if (p != cur) {
                            uf.unite(p, cur);
                            incoming_edges[cur].merge(incoming_edges[p]);
                        }
                        p = uf.find(from[p]);
                    } while (p != cur);
                } else {
                    cur = from[cur];
                }
            }
            for (int v : processing) used[v] = 2;
        }
    }
};
template <>
std::vector<MinimumSpanningArborescence<long long>::skew_heap::node>
    MinimumSpanningArborescence<long long>::skew_heap::data = {};
template <typename T> unsigned MinimumSpanningArborescence<T>::skew_heap::len = 0;
#line 2 "graph/test/directed_mst.aoj.test.cpp"
#include <iostream>
using namespace std;
#define PROBLEM "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_2_B"

int main() {
    int N, M, S;
    cin >> N >> M >> S;
    std::vector<std::tuple<int, int, long long>> edges;
    while (M--) {
        int a, b, c;
        cin >> a >> b >> c;
        edges.emplace_back(a, b, c);
    }
    MinimumSpanningArborescence<long long> msa(N, edges, S);
    cout << msa.ret << '\n';
}
Back to top page