m1une's library

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

View on GitHub

:heavy_check_mark: Flow
(graph/flow/flow.hpp)

Overview

graph/flow/flow.hpp includes flow-network algorithms. Flow networks are directed: an edge u -> v only sends flow from u to v.

For an undirected capacity between u and v, MaxFlow provides add_undirected_edge(u, v, cap), which stores one shared-capacity residual pair. Other directed-flow classes represent it with two directed edges.

Included Headers

Header Graph orientation Contents
graph/flow/bounded_flow.hpp Directed flow network Feasible flow with lower/upper bounds, balances, and negative flow intervals.
graph/flow/bounded_min_cost_flow.hpp Directed flow network Minimum-cost feasible flow with lower/upper bounds, balances, and negative flow intervals.
graph/flow/gomory_hu.hpp Undirected capacitated graph Gomory-Hu cut tree and pairwise minimum-cut queries.
graph/flow/max_flow.hpp Directed or shared-capacity undirected network $O(N^2 \sqrt M)$ highest-label preflow-push, flow-limited Dinic, and minimum cut.
graph/flow/min_cost_flow.hpp Directed flow network Minimum-cost flow with potentials.

Complexity

This header is an include bundle and provides no runtime operation by itself. See the included algorithm pages for public interfaces and complexities.

Depends on

Required by

Verified with

Code

#ifndef M1UNE_FLOW_FLOW_HPP
#define M1UNE_FLOW_FLOW_HPP 1

#include "bounded_flow.hpp"
#include "bounded_min_cost_flow.hpp"
#include "gomory_hu.hpp"
#include "max_flow.hpp"
#include "min_cost_flow.hpp"

#endif  // M1UNE_FLOW_FLOW_HPP
#line 1 "graph/flow/flow.hpp"



#line 1 "graph/flow/bounded_flow.hpp"



#include <cassert>
#include <optional>
#include <vector>

#line 1 "graph/flow/max_flow.hpp"



#include <algorithm>
#line 6 "graph/flow/max_flow.hpp"
#include <cstddef>
#include <limits>
#line 9 "graph/flow/max_flow.hpp"

namespace m1une {
namespace flow {

template <class Cap>
struct MaxFlow {
    struct Edge {
        int from;
        int to;
        Cap cap;
        Cap flow;
    };

   private:
    struct InternalEdge {
        int to;
        int rev;
        Cap cap;
    };

    struct Position {
        int from;
        int edge;
    };

    int _n;
    std::vector<Position> _pos;
    std::vector<std::vector<InternalEdge>> _g;

    Cap highest_label_preflow_push(int s, int t) {
        const int dead = 2 * _n;
        const int unreachable = _n + 1;
        std::vector<Cap> excess(_n, Cap(0));
        std::vector<int> state(8 * std::size_t(_n) + 2);
        int* height = state.data();
        int* height_count = height + _n;
        int* current = height_count + dead + 1;
        int* queue = current + _n;
        int* next = queue + _n;
        int* bucket_head = next + _n;
        std::vector<char> active(_n, false);
        int highest = -1;
        long long work = 0;
        const long long arc_count =
            2LL * static_cast<long long>(_pos.size());
        const long long work_limit = std::max(1LL, 4 * arc_count + _n);

        auto activate = [&](int v) {
            if (v == s || v == t || active[v] || excess[v] == Cap(0) ||
                height[v] >= dead) {
                return;
            }
            active[v] = true;
            next[v] = bucket_head[height[v]];
            bucket_head[height[v]] = v;
            highest = std::max(highest, height[v]);
        };

        auto rebuild_buckets = [&]() {
            std::fill(bucket_head, bucket_head + dead + 1, -1);
            std::fill(active.begin(), active.end(), false);
            highest = -1;
            for (int v = 0; v < _n; v++) activate(v);
        };

        auto global_relabel = [&]() {
            std::fill(height, height + _n, unreachable);
            std::fill(height_count, height_count + dead + 1, 0);
            std::fill(current, current + _n, 0);
            int head = 0;
            int tail = 0;
            height[t] = 0;
            height[s] = _n;
            queue[tail++] = t;
            while (head != tail) {
                int v = queue[head++];
                for (const auto& e : _g[v]) {
                    if (e.to == s || height[e.to] != unreachable) continue;
                    const auto& reverse = _g[e.to][e.rev];
                    if (reverse.cap == Cap(0)) continue;
                    height[e.to] = height[v] + 1;
                    queue[tail++] = e.to;
                }
            }
            for (int v = 0; v < _n; v++) height_count[height[v]]++;
            rebuild_buckets();
            work = 0;
        };

        auto gap = [&](int empty_height) {
            for (int v = 0; v < _n; v++) {
                if (v == s || v == t || height[v] <= empty_height ||
                    height[v] >= _n) {
                    continue;
                }
                height_count[height[v]]--;
                height[v] = unreachable;
                height_count[height[v]]++;
                current[v] = 0;
            }
            rebuild_buckets();
        };

        auto relabel = [&](int v) -> bool {
            int old_height = height[v];
            int new_height = dead;
            work += int(_g[v].size());
            for (const auto& e : _g[v]) {
                if (e.cap != Cap(0)) {
                    new_height = std::min(new_height, height[e.to] + 1);
                }
            }
            height_count[old_height]--;
            height[v] = std::min(new_height, dead);
            height_count[height[v]]++;
            current[v] = 0;
            if (old_height < _n && height_count[old_height] == 0) {
                gap(old_height);
                return true;
            }
            return false;
        };

        auto push = [&](int v, InternalEdge& e) {
            Cap sent = std::min(excess[v], e.cap);
            bool was_zero = excess[e.to] == Cap(0);
            e.cap -= sent;
            _g[e.to][e.rev].cap += sent;
            excess[v] -= sent;
            excess[e.to] += sent;
            if (was_zero) activate(e.to);
        };

        auto discharge = [&](int v) {
            while (excess[v] != Cap(0) && height[v] < dead) {
                if (current[v] == int(_g[v].size())) {
                    if (relabel(v)) return;
                    continue;
                }
                auto& e = _g[v][current[v]];
                work++;
                if (e.cap != Cap(0) && height[v] == height[e.to] + 1) {
                    push(v, e);
                } else {
                    current[v]++;
                }
            }
            activate(v);
        };

        for (auto& e : _g[s]) {
            if (e.to == s || e.cap == Cap(0)) continue;
            Cap sent = e.cap;
            e.cap = Cap(0);
            _g[e.to][e.rev].cap += sent;
            excess[e.to] += sent;
        }
        global_relabel();

        while (highest >= 0) {
            if (bucket_head[highest] == -1) {
                highest--;
                continue;
            }
            int v = bucket_head[highest];
            bucket_head[highest] = next[v];
            if (!active[v] || height[v] != highest) continue;
            active[v] = false;
            discharge(v);
            if (work >= work_limit) global_relabel();
        }
        return excess[t];
    }

   public:
    MaxFlow() : MaxFlow(0) {}

    explicit MaxFlow(int n) : _n(n), _g(n) {
        assert(0 <= n);
    }

    int size() const {
        return _n;
    }

    int edge_count() const {
        return int(_pos.size());
    }

    void reserve_edges(int edge_count) {
        assert(0 <= edge_count);
        _pos.reserve(edge_count);
        if (_n == 0 || edge_count == 0 ||
            2 * std::size_t(edge_count) < std::size_t(_n)) {
            return;
        }
        const std::size_t average_degree =
            (3 * std::size_t(edge_count) + std::size_t(_n) - 1)
            / std::size_t(_n);
        for (auto& edges : _g) edges.reserve(average_degree);
    }

    void reserve_edges(int edge_count, const std::vector<int>& degrees) {
        assert(0 <= edge_count);
        assert(int(degrees.size()) == _n);
        _pos.reserve(edge_count);
        for (int v = 0; v < _n; v++) {
            assert(0 <= degrees[v]);
            _g[v].reserve(degrees[v]);
        }
    }

    int add_edge(int from, int to, Cap cap) {
        assert(0 <= from && from < _n);
        assert(0 <= to && to < _n);
        assert(Cap(0) <= cap);
        int id = int(_pos.size());
        int from_id = int(_g[from].size());
        int to_id = int(_g[to].size());
        if (from == to) to_id++;
        _pos.push_back(Position{from, from_id});
        _g[from].push_back(InternalEdge{to, to_id, cap});
        _g[to].push_back(InternalEdge{from, from_id, Cap(0)});
        return id;
    }

    int add_undirected_edge(int first, int second, Cap cap) {
        static_assert(std::numeric_limits<Cap>::is_signed);
        assert(0 <= first && first < _n);
        assert(0 <= second && second < _n);
        assert(Cap(0) <= cap);
        assert(cap <= std::numeric_limits<Cap>::max() / Cap(2));
        int id = int(_pos.size());
        int first_id = int(_g[first].size());
        int second_id = int(_g[second].size());
        if (first == second) second_id++;
        _pos.push_back(Position{first, ~first_id});
        _g[first].push_back(InternalEdge{second, second_id, cap});
        _g[second].push_back(InternalEdge{first, first_id, cap});
        return id;
    }

    Edge get_edge(int i) const {
        assert(0 <= i && i < int(_pos.size()));
        const auto& position = _pos[i];
        int from = position.from;
        bool undirected = position.edge < 0;
        int idx = undirected ? ~position.edge : position.edge;
        const auto& e = _g[from][idx];
        const auto& re = _g[e.to][e.rev];
        if (undirected) {
            return Edge{
                from,
                e.to,
                (e.cap + re.cap) / Cap(2),
                (re.cap - e.cap) / Cap(2)
            };
        }
        return Edge{from, e.to, e.cap + re.cap, re.cap};
    }

    std::vector<Edge> edges() const {
        std::vector<Edge> result;
        result.reserve(_pos.size());
        for (int i = 0; i < int(_pos.size()); i++) result.push_back(get_edge(i));
        return result;
    }

    void change_edge(int i, Cap new_cap, Cap new_flow) {
        assert(0 <= i && i < int(_pos.size()));
        assert(Cap(0) <= new_cap);
        auto& position = _pos[i];
        int from = position.from;
        bool undirected = position.edge < 0;
        int idx = undirected ? ~position.edge : position.edge;
        auto& e = _g[from][idx];
        auto& re = _g[e.to][e.rev];
        if (undirected) {
            assert(new_cap <= std::numeric_limits<Cap>::max() / Cap(2));
            assert(-new_cap <= new_flow && new_flow <= new_cap);
            e.cap = new_cap - new_flow;
            re.cap = new_cap + new_flow;
        } else {
            assert(Cap(0) <= new_flow && new_flow <= new_cap);
            e.cap = new_cap - new_flow;
            re.cap = new_flow;
        }
    }

    Cap max_flow(int s, int t) {
        assert(0 <= s && s < _n);
        assert(0 <= t && t < _n);
        assert(s != t);
        return highest_label_preflow_push(s, t);
    }

    Cap max_flow_push_relabel(int s, int t) {
        assert(0 <= s && s < _n);
        assert(0 <= t && t < _n);
        assert(s != t);
        return highest_label_preflow_push(s, t);
    }

    Cap max_flow_dinic(int s, int t) {
        return max_flow(s, t, std::numeric_limits<Cap>::max());
    }

    Cap max_flow(int s, int t, Cap flow_limit) {
        assert(0 <= s && s < _n);
        assert(0 <= t && t < _n);
        assert(s != t);

        std::vector<int> work(3 * std::size_t(_n));
        int* level = work.data();
        int* iter = level + _n;
        int* queue = iter + _n;
        auto bfs = [&]() -> bool {
            std::fill(level, level + _n, -1);
            int head = 0;
            int tail = 0;
            level[s] = 0;
            queue[tail++] = s;
            while (head != tail) {
                int v = queue[head++];
                for (const auto& e : _g[v]) {
                    if (level[e.to] != -1 || e.cap == Cap(0)) continue;
                    level[e.to] = level[v] + 1;
                    if (e.to == t) return true;
                    queue[tail++] = e.to;
                }
            }
            return level[t] != -1;
        };

        auto dfs = [&](auto&& self, int v, Cap up) -> Cap {
            if (v == s) return up;
            Cap result = Cap(0);
            const int current_level = level[v];
            auto& edges = _g[v];
            const int edge_count = int(edges.size());
            for (int& i = iter[v]; i < edge_count; i++) {
                auto& e = edges[i];
                if (level[e.to] + 1 != current_level) continue;
                auto& reverse = _g[e.to][e.rev];
                if (reverse.cap == Cap(0)) continue;
                Cap d = self(
                    self,
                    e.to,
                    std::min(up - result, reverse.cap)
                );
                if (d == Cap(0)) continue;
                e.cap += d;
                reverse.cap -= d;
                result += d;
                if (result == up) return result;
            }
            level[v] = _n;
            return result;
        };

        Cap flow = 0;
        while (flow < flow_limit && bfs()) {
            std::fill(iter, iter + _n, 0);
            flow += dfs(dfs, t, flow_limit - flow);
        }
        return flow;
    }

    std::vector<bool> min_cut(int s) const {
        assert(0 <= s && s < _n);
        std::vector<bool> visited(_n, false);
        std::vector<int> queue(_n);
        int head = 0;
        int tail = 0;
        visited[s] = true;
        queue[tail++] = s;
        while (head != tail) {
            int v = queue[head++];
            for (const auto& e : _g[v]) {
                if (e.cap == Cap(0) || visited[e.to]) continue;
                visited[e.to] = true;
                queue[tail++] = e.to;
            }
        }
        return visited;
    }
};

}  // namespace flow
}  // namespace m1une


#line 9 "graph/flow/bounded_flow.hpp"

namespace m1une {
namespace flow {

template <class Cap>
struct BoundedFlow {
    struct Edge {
        int from;
        int to;
        Cap lower;
        Cap upper;
    };

    struct ResultEdge {
        int from;
        int to;
        Cap lower;
        Cap upper;
        Cap flow;
    };

    struct Result {
        std::vector<ResultEdge> edges;
        std::vector<Cap> balance;

        ResultEdge get_edge(int i) const {
            assert(0 <= i && i < int(edges.size()));
            return edges[i];
        }

        Cap flow(int i) const {
            assert(0 <= i && i < int(edges.size()));
            return edges[i].flow;
        }
    };

   private:
    int _n;
    std::vector<Edge> _edges;
    std::vector<Cap> _balance;

   public:
    BoundedFlow() : BoundedFlow(0) {}

    explicit BoundedFlow(int n) : _n(n), _balance(n, Cap(0)) {
        assert(0 <= n);
    }

    int size() const {
        return _n;
    }

    int edge_count() const {
        return int(_edges.size());
    }

    int add_edge(int from, int to, Cap lower, Cap upper) {
        assert(0 <= from && from < _n);
        assert(0 <= to && to < _n);
        assert(lower <= upper);
        int id = int(_edges.size());
        _edges.push_back(Edge{from, to, lower, upper});
        return id;
    }

    Edge get_edge(int i) const {
        assert(0 <= i && i < int(_edges.size()));
        return _edges[i];
    }

    std::vector<Edge> edges() const {
        return _edges;
    }

    void set_balance(int v, Cap b) {
        assert(0 <= v && v < _n);
        _balance[v] = b;
    }

    void add_balance(int v, Cap b) {
        assert(0 <= v && v < _n);
        _balance[v] += b;
    }

    void add_supply(int v, Cap supply) {
        assert(Cap(0) <= supply);
        add_balance(v, supply);
    }

    void add_demand(int v, Cap demand) {
        assert(Cap(0) <= demand);
        add_balance(v, -demand);
    }

    Cap balance(int v) const {
        assert(0 <= v && v < _n);
        return _balance[v];
    }

    const std::vector<Cap>& balances() const {
        return _balance;
    }

    std::optional<Result> feasible_flow() const {
        return feasible_flow(_balance);
    }

    std::optional<Result> feasible_flow(const std::vector<Cap>& balance) const {
        assert(int(balance.size()) == _n);
        int ss = _n, tt = _n + 1;
        MaxFlow<Cap> mf(_n + 2);
        std::vector<int> edge_ids;
        edge_ids.reserve(_edges.size());

        std::vector<Cap> need = balance;
        for (const auto& e : _edges) {
            edge_ids.push_back(mf.add_edge(e.from, e.to, e.upper - e.lower));
            need[e.from] -= e.lower;
            need[e.to] += e.lower;
        }

        Cap positive_sum = Cap(0), negative_sum = Cap(0);
        for (int v = 0; v < _n; v++) {
            if (need[v] > Cap(0)) {
                positive_sum += need[v];
                mf.add_edge(ss, v, need[v]);
            } else if (need[v] < Cap(0)) {
                negative_sum += -need[v];
                mf.add_edge(v, tt, -need[v]);
            }
        }
        if (positive_sum != negative_sum) return std::nullopt;
        if (mf.max_flow(ss, tt) != positive_sum) return std::nullopt;

        Result result;
        result.balance = balance;
        result.edges.reserve(_edges.size());
        for (int i = 0; i < int(_edges.size()); i++) {
            auto used = mf.get_edge(edge_ids[i]).flow;
            const auto& e = _edges[i];
            result.edges.push_back(ResultEdge{e.from, e.to, e.lower, e.upper, e.lower + used});
        }
        return result;
    }

    std::optional<Result> feasible_st_flow(int s, int t, Cap flow_value) const {
        assert(0 <= s && s < _n);
        assert(0 <= t && t < _n);
        assert(s != t);
        std::vector<Cap> balance = _balance;
        balance[s] += flow_value;
        balance[t] -= flow_value;
        return feasible_flow(balance);
    }
};

template <class Cap>
using BFlow = BoundedFlow<Cap>;

}  // namespace flow
}  // namespace m1une


#line 1 "graph/flow/bounded_min_cost_flow.hpp"



#line 7 "graph/flow/bounded_min_cost_flow.hpp"
#include <cmath>
#include <functional>
#line 11 "graph/flow/bounded_min_cost_flow.hpp"
#include <queue>
#include <utility>
#line 14 "graph/flow/bounded_min_cost_flow.hpp"

namespace m1une {
namespace flow {

template <
    class Cap,
    class Cost,
    class TotalCost = Cost,
    std::size_t PivotLimitFactor = 8
>
struct BoundedMinCostFlow {
    static_assert(std::numeric_limits<Cap>::is_integer);
    static_assert(std::numeric_limits<Cap>::is_signed);
    static_assert(std::numeric_limits<Cost>::is_specialized);
    static_assert(std::numeric_limits<Cost>::is_signed);

    struct Edge {
        int from;
        int to;
        Cap lower;
        Cap upper;
        Cost cost;
    };

    struct ResultEdge {
        int from;
        int to;
        Cap lower;
        Cap upper;
        Cap flow;
        Cost cost;
    };

    struct Result {
        std::vector<ResultEdge> edges;
        std::vector<Cap> balance;
        std::vector<Cost> potential;
        TotalCost cost;

        ResultEdge get_edge(int i) const {
            assert(0 <= i && i < int(edges.size()));
            return edges[i];
        }

        Cap flow(int i) const {
            assert(0 <= i && i < int(edges.size()));
            return edges[i].flow;
        }
    };

   private:
    struct NetworkEdge {
        int to;
        Cap cap;
        Cost cost;
    };

    struct NetworkSimplexSolver {
        enum class Status {
            optimal,
            infeasible,
            pivot_limit_reached,
        };

        struct Parent {
            int vertex;
            int edge;
            Cap up;
            Cap down;
        };

        int n;
        std::vector<NetworkEdge> edges;
        std::vector<Cap> excess;
        std::vector<Cost> potential;
        std::size_t pivot_count = 0;

        NetworkSimplexSolver(int vertex_count, const std::vector<Cap>& balance)
            : n(vertex_count), excess(balance) {}

        void reserve_edges(int edge_count) {
            edges.reserve(2 * (edge_count + n));
        }

        int add_edge(int from, int to, Cap lower, Cap upper, Cost cost) {
            int id = int(edges.size()) / 2;
            edges.push_back(NetworkEdge{to, upper - lower, cost});
            edges.push_back(NetworkEdge{from, Cap(0), -cost});
            excess[from] -= lower;
            excess[to] += lower;
            return id;
        }

        Status solve(std::size_t pivot_limit) {
            pivot_count = 0;
            const int original_edge_count = int(edges.size());
            potential.assign(n + 1, Cost(0));

            Cost artificial_cost = Cost(1);
            for (int edge = 0; edge < original_edge_count; edge += 2) {
                artificial_cost += edges[edge].cost < Cost(0)
                    ? -edges[edge].cost : edges[edge].cost;
            }

            std::vector<Parent> parent(n);
            edges.reserve(original_edge_count + 2 * n);
            for (int vertex = 0; vertex < n; vertex++) {
                if (excess[vertex] >= Cap(0)) {
                    edges.push_back(NetworkEdge{n, Cap(0), artificial_cost});
                    edges.push_back(NetworkEdge{vertex, excess[vertex], -artificial_cost});
                    potential[vertex] = -artificial_cost;
                } else {
                    edges.push_back(NetworkEdge{n, -excess[vertex], -artificial_cost});
                    edges.push_back(NetworkEdge{vertex, Cap(0), artificial_cost});
                    potential[vertex] = artificial_cost;
                }
                int edge = int(edges.size()) - 2;
                parent[vertex] = Parent{
                    n, edge, edges[edge].cap, edges[edge ^ 1].cap
                };
            }

            std::vector<int> depth(n + 1, 1);
            depth[n] = 0;
            std::vector<int> next(2 * (n + 1));
            std::vector<int> previous(2 * (n + 1));
            auto connect = [&](int first, int second) {
                next[first] = second;
                previous[second] = first;
            };
            for (int vertex = 0; vertex <= n; vertex++) {
                connect(2 * vertex, 2 * vertex + 1);
            }
            for (int vertex = 0; vertex < n; vertex++) {
                connect(2 * vertex + 1, next[2 * n]);
                connect(2 * n, 2 * vertex);
            }

            auto push_flow = [&](int entering_edge) {
                const int first = edges[entering_edge ^ 1].to;
                const int second = edges[entering_edge].to;
                const Cost cycle_cost =
                    edges[entering_edge].cost
                    + potential[first] - potential[second];

                Cap amount = edges[entering_edge].cap;
                bool leave_first_side = true;
                int leaving_vertex = second;

                int first_ancestor = first;
                int second_ancestor = second;
                auto move_first_up = [&] {
                    if (parent[first_ancestor].down < amount) {
                        amount = parent[first_ancestor].down;
                        leaving_vertex = first_ancestor;
                        leave_first_side = true;
                    }
                    first_ancestor = parent[first_ancestor].vertex;
                };
                auto move_second_up = [&] {
                    if (parent[second_ancestor].up <= amount) {
                        amount = parent[second_ancestor].up;
                        leaving_vertex = second_ancestor;
                        leave_first_side = false;
                    }
                    second_ancestor = parent[second_ancestor].vertex;
                };
                if (depth[first_ancestor] >= depth[second_ancestor]) {
                    int difference = depth[first_ancestor] - depth[second_ancestor];
                    for (int i = 0; i < difference; i++) move_first_up();
                } else {
                    int difference = depth[second_ancestor] - depth[first_ancestor];
                    for (int i = 0; i < difference; i++) move_second_up();
                }
                while (first_ancestor != second_ancestor) {
                    move_first_up();
                    move_second_up();
                }
                const int ancestor = first_ancestor;

                if (amount != Cap(0)) {
                    int vertex = first;
                    while (vertex != ancestor) {
                        parent[vertex].up += amount;
                        parent[vertex].down -= amount;
                        vertex = parent[vertex].vertex;
                    }
                    vertex = second;
                    while (vertex != ancestor) {
                        parent[vertex].up -= amount;
                        parent[vertex].down += amount;
                        vertex = parent[vertex].vertex;
                    }
                }

                int vertex = first;
                int new_parent = second;
                std::pair<Cap, Cap> parent_capacities{
                    edges[entering_edge].cap - amount,
                    edges[entering_edge ^ 1].cap + amount
                };
                Cost potential_difference = -cycle_cost;
                if (!leave_first_side) {
                    std::swap(vertex, new_parent);
                    std::swap(parent_capacities.first, parent_capacities.second);
                    potential_difference = -potential_difference;
                }
                int parent_edge = entering_edge ^ (leave_first_side ? 0 : 1);

                while (new_parent != leaving_vertex) {
                    int new_depth = depth[new_parent];
                    int tour_index = 2 * vertex;
                    while (tour_index != 2 * vertex + 1) {
                        if ((tour_index & 1) == 0) {
                            new_depth++;
                            potential[tour_index / 2] += potential_difference;
                            depth[tour_index / 2] = new_depth;
                        } else {
                            new_depth--;
                        }
                        tour_index = next[tour_index];
                    }

                    connect(previous[2 * vertex], next[2 * vertex + 1]);
                    connect(2 * vertex + 1, next[2 * new_parent]);
                    connect(2 * new_parent, 2 * vertex);

                    std::swap(parent[vertex].edge, parent_edge);
                    parent_edge ^= 1;
                    std::swap(parent[vertex].up, parent_capacities.first);
                    std::swap(parent[vertex].down, parent_capacities.second);
                    std::swap(parent_capacities.first, parent_capacities.second);

                    int old_parent = parent[vertex].vertex;
                    parent[vertex].vertex = new_parent;
                    new_parent = vertex;
                    vertex = old_parent;
                }
                edges[parent_edge].cap = parent_capacities.first;
                edges[parent_edge ^ 1].cap = parent_capacities.second;
            };

            bool pivot_limit_reached = false;
            auto pivot = [&](int entering_edge) {
                if (pivot_count == pivot_limit) {
                    pivot_limit_reached = true;
                    return false;
                }
                push_flow(entering_edge);
                pivot_count++;
                return true;
            };

            const int candidate_limit = std::max(
                int(0.2 * std::sqrt(double(original_edge_count))), 10
            );
            const int minor_limit = std::max(candidate_limit / 10, 3);
            std::vector<int> candidates;
            candidates.reserve(candidate_limit);

            auto minor_pivot = [&] {
                Cost best_cost = Cost(0);
                int best_edge = -1;
                int index = 0;
                while (index < int(candidates.size())) {
                    int edge = candidates[index];
                    if (edges[edge].cap == Cap(0)) {
                        candidates[index] = candidates.back();
                        candidates.pop_back();
                        continue;
                    }
                    Cost reduced_cost =
                        edges[edge].cost
                        + potential[edges[edge ^ 1].to]
                        - potential[edges[edge].to];
                    if (reduced_cost >= Cost(0)) {
                        candidates[index] = candidates.back();
                        candidates.pop_back();
                        continue;
                    }
                    if (reduced_cost < best_cost) {
                        best_cost = reduced_cost;
                        best_edge = edge;
                    }
                    index++;
                }
                if (best_edge == -1) return false;
                return pivot(best_edge);
            };

            int edge = 0;
            while (true) {
                for (int iteration = 0; iteration < minor_limit; iteration++) {
                    if (!minor_pivot()) break;
                }
                if (pivot_limit_reached) return Status::pivot_limit_reached;

                Cost best_cost = Cost(0);
                int best_edge = -1;
                candidates.clear();
                for (int scanned = 0; scanned < int(edges.size()); scanned++) {
                    if (edges[edge].cap != Cap(0)) {
                        Cost reduced_cost =
                            edges[edge].cost
                            + potential[edges[edge ^ 1].to]
                            - potential[edges[edge].to];
                        if (reduced_cost < Cost(0)) {
                            if (reduced_cost < best_cost) {
                                best_cost = reduced_cost;
                                best_edge = edge;
                            }
                            candidates.push_back(edge);
                            if (int(candidates.size()) == candidate_limit) break;
                        }
                    }
                    edge++;
                    if (edge == int(edges.size())) edge = 0;
                }
                if (candidates.empty()) break;
                if (!pivot(best_edge)) return Status::pivot_limit_reached;
            }

            for (int vertex = 0; vertex < n; vertex++) {
                edges[parent[vertex].edge].cap = parent[vertex].up;
                edges[parent[vertex].edge ^ 1].cap = parent[vertex].down;
            }

            bool feasible = true;
            for (int vertex = 0; vertex < n; vertex++) {
                int artificial_edge = original_edge_count + 2 * vertex;
                if (
                    (excess[vertex] >= Cap(0)
                        && edges[artificial_edge ^ 1].cap != Cap(0))
                    || (excess[vertex] < Cap(0)
                        && edges[artificial_edge].cap != Cap(0))
                ) {
                    feasible = false;
                    break;
                }
            }
            potential.pop_back();
            return feasible ? Status::optimal : Status::infeasible;
        }

        Cap edge_flow(int edge_id, Cap lower) const {
            return lower + edges[2 * edge_id + 1].cap;
        }
    };

    struct ScalingEdge {
        int to;
        int reverse;
        Cap cap;
        Cap flow;
        Cost cost;
    };

    struct ScalingSolver {
        int n;
        std::vector<std::vector<ScalingEdge>> graph;
        std::vector<std::pair<int, int>> positions;
        std::vector<Cap> excess;
        std::vector<Cost> potential;
        std::vector<Cost> distance;
        std::vector<int> parent_vertex;
        std::vector<int> parent_edge;
        std::vector<int> excess_vertices;
        std::vector<int> deficit_vertices;
        Cost farthest = Cost(0);

        ScalingSolver(int vertex_count, const std::vector<Cap>& balance)
            : n(vertex_count), graph(vertex_count), excess(balance),
              potential(vertex_count, Cost(0)) {}

        void reserve_edges(int edge_count) {
            positions.reserve(edge_count);
        }

        int add_edge(int from, int to, Cap lower, Cap upper, Cost cost) {
            int id = int(positions.size());
            int from_edge = int(graph[from].size());
            int to_edge = int(graph[to].size());
            if (from == to) to_edge++;
            positions.emplace_back(from, from_edge);
            graph[from].push_back(ScalingEdge{
                to, to_edge, upper, Cap(0), cost
            });
            graph[to].push_back(ScalingEdge{
                from, from_edge, -lower, Cap(0), -cost
            });
            return id;
        }

        Cap residual_capacity(int from, int edge_id) const {
            const auto& edge = graph[from][edge_id];
            return edge.cap - edge.flow;
        }

        Cost residual_cost(int from, const ScalingEdge& edge) const {
            return edge.cost + potential[from] - potential[edge.to];
        }

        void push(int from, int edge_id, Cap amount) {
            auto& edge = graph[from][edge_id];
            edge.flow += amount;
            graph[edge.to][edge.reverse].flow -= amount;
        }

        void saturate_negative(Cap delta) {
            excess_vertices.clear();
            deficit_vertices.clear();
            for (int from = 0; from < n; from++) {
                for (
                    int edge_id = 0;
                    edge_id < int(graph[from].size());
                    edge_id++
                ) {
                    const auto& edge = graph[from][edge_id];
                    Cap residual = edge.cap - edge.flow;
                    residual -= residual % delta;
                    if (
                        residual_cost(from, edge) < Cost(0)
                        || residual < Cap(0)
                    ) {
                        int to = edge.to;
                        push(from, edge_id, residual);
                        excess[from] -= residual;
                        excess[to] += residual;
                    }
                }
            }
            for (int vertex = 0; vertex < n; vertex++) {
                if (excess[vertex] > Cap(0)) {
                    excess_vertices.push_back(vertex);
                } else if (excess[vertex] < Cap(0)) {
                    deficit_vertices.push_back(vertex);
                }
            }
        }

        bool dual(Cap delta) {
            excess_vertices.erase(
                std::remove_if(
                    excess_vertices.begin(), excess_vertices.end(),
                    [&](int vertex) { return excess[vertex] < delta; }
                ),
                excess_vertices.end()
            );
            deficit_vertices.erase(
                std::remove_if(
                    deficit_vertices.begin(), deficit_vertices.end(),
                    [&](int vertex) { return excess[vertex] > -delta; }
                ),
                deficit_vertices.end()
            );

            const Cost unreachable = std::numeric_limits<Cost>::max();
            distance.assign(n, unreachable);
            parent_vertex.assign(n, -1);
            parent_edge.assign(n, -1);
            using QueueEntry = std::pair<Cost, int>;
            std::priority_queue<
                QueueEntry,
                std::vector<QueueEntry>,
                std::greater<QueueEntry>
            > queue;
            for (int vertex : excess_vertices) {
                distance[vertex] = Cost(0);
                queue.emplace(Cost(0), vertex);
            }

            farthest = Cost(0);
            int reached_deficits = 0;
            while (!queue.empty()) {
                auto [current_distance, from] = queue.top();
                queue.pop();
                if (distance[from] != current_distance) continue;
                farthest = current_distance;
                if (excess[from] <= -delta) reached_deficits++;
                if (reached_deficits >= int(deficit_vertices.size())) break;

                for (
                    int edge_id = 0;
                    edge_id < int(graph[from].size());
                    edge_id++
                ) {
                    const auto& edge = graph[from][edge_id];
                    if (edge.cap - edge.flow < delta) continue;
                    Cost next_distance =
                        current_distance + residual_cost(from, edge);
                    if (next_distance >= distance[edge.to]) continue;
                    distance[edge.to] = next_distance;
                    parent_vertex[edge.to] = from;
                    parent_edge[edge.to] = edge_id;
                    queue.emplace(next_distance, edge.to);
                }
            }

            for (int vertex = 0; vertex < n; vertex++) {
                potential[vertex] += std::min(distance[vertex], farthest);
            }
            return reached_deficits > 0;
        }

        void primal(Cap delta) {
            for (int sink : deficit_vertices) {
                if (distance[sink] > farthest) continue;
                Cap amount = -excess[sink];
                int root = sink;
                while (parent_edge[root] != -1) {
                    int from = parent_vertex[root];
                    amount = std::min(
                        amount,
                        residual_capacity(from, parent_edge[root])
                    );
                    root = from;
                }
                amount = std::min(amount, excess[root]);
                amount -= amount % delta;
                if (amount <= Cap(0)) continue;

                int vertex = sink;
                while (parent_edge[vertex] != -1) {
                    int from = parent_vertex[vertex];
                    int edge_id = parent_edge[vertex];
                    push(from, edge_id, amount);
                    if (residual_capacity(from, edge_id) == Cap(0)) {
                        parent_edge[vertex] = -1;
                    }
                    vertex = from;
                }
                excess[sink] += amount;
                excess[root] -= amount;
            }
        }

        bool solve() {
            Cap scale_bound = Cap(1);
            for (Cap value : excess) {
                scale_bound = std::max(scale_bound, value);
                scale_bound = std::max(scale_bound, -value);
            }
            for (const auto& edges : graph) {
                for (const auto& edge : edges) {
                    Cap residual = edge.cap - edge.flow;
                    scale_bound = std::max(scale_bound, residual);
                    scale_bound = std::max(scale_bound, -residual);
                }
            }

            Cap delta = Cap(1);
            while (delta <= scale_bound / Cap(2)) delta *= Cap(2);
            while (true) {
                saturate_negative(delta);
                while (dual(delta)) primal(delta);
                if (delta == Cap(1)) break;
                delta /= Cap(2);
            }
            return excess_vertices.empty() && deficit_vertices.empty();
        }

        Cap edge_flow(int edge_id, Cap) const {
            auto [from, index] = positions[edge_id];
            return graph[from][index].flow;
        }
    };

    int _n;
    std::vector<Edge> _edges;
    std::vector<Cap> _balance;

    template <class Solver>
    Result make_result(
        const std::vector<Cap>& balance,
        const Solver& solver,
        std::vector<Cost> potential
    ) const {
        Result result;
        result.balance = balance;
        result.cost = TotalCost(0);
        result.edges.reserve(_edges.size());
        for (int i = 0; i < int(_edges.size()); i++) {
            const auto& edge = _edges[i];
            Cap flow = solver.edge_flow(i, edge.lower);
            result.cost += TotalCost(flow) * TotalCost(edge.cost);
            result.edges.push_back(ResultEdge{
                edge.from,
                edge.to,
                edge.lower,
                edge.upper,
                flow,
                edge.cost
            });
        }
        result.potential = std::move(potential);
        return result;
    }

    std::vector<Cost> residual_potential(
        const std::vector<ResultEdge>& edges
    ) const {
        std::vector<Cost> potential(_n, Cost(0));
        bool updated = false;
        for (int iteration = 0; iteration < _n; iteration++) {
            updated = false;
            for (const ResultEdge& edge : edges) {
                if (
                    edge.flow < edge.upper
                    && potential[edge.to] > potential[edge.from] + edge.cost
                ) {
                    potential[edge.to] = potential[edge.from] + edge.cost;
                    updated = true;
                }
                if (
                    edge.lower < edge.flow
                    && potential[edge.from] > potential[edge.to] - edge.cost
                ) {
                    potential[edge.from] = potential[edge.to] - edge.cost;
                    updated = true;
                }
            }
            if (!updated) break;
        }
        assert(!updated);
        return potential;
    }

    std::optional<Result> polynomial_min_cost_flow_impl(
        const std::vector<Cap>& balance
    ) const {
        ScalingSolver solver(_n, balance);
        solver.reserve_edges(int(_edges.size()));
        for (const auto& edge : _edges) {
            solver.add_edge(
                edge.from,
                edge.to,
                edge.lower,
                edge.upper,
                edge.cost
            );
        }
        if (!solver.solve()) return std::nullopt;

        Result result = make_result(balance, solver, {});
        result.potential = residual_potential(result.edges);
        return result;
    }

   public:
    BoundedMinCostFlow() : BoundedMinCostFlow(0) {}

    explicit BoundedMinCostFlow(int n) : _n(n), _balance(n, Cap(0)) {
        assert(0 <= n);
    }

    int size() const {
        return _n;
    }

    int edge_count() const {
        return int(_edges.size());
    }

    void reserve_edges(int edge_count) {
        assert(0 <= edge_count);
        _edges.reserve(edge_count);
    }

    int add_edge(int from, int to, Cap lower, Cap upper, Cost cost) {
        assert(0 <= from && from < _n);
        assert(0 <= to && to < _n);
        assert(lower <= upper);
        int id = int(_edges.size());
        _edges.push_back(Edge{from, to, lower, upper, cost});
        return id;
    }

    Edge get_edge(int i) const {
        assert(0 <= i && i < int(_edges.size()));
        return _edges[i];
    }

    std::vector<Edge> edges() const {
        return _edges;
    }

    void set_balance(int v, Cap b) {
        assert(0 <= v && v < _n);
        _balance[v] = b;
    }

    void add_balance(int v, Cap b) {
        assert(0 <= v && v < _n);
        _balance[v] += b;
    }

    void add_supply(int v, Cap supply) {
        assert(Cap(0) <= supply);
        add_balance(v, supply);
    }

    void add_demand(int v, Cap demand) {
        assert(Cap(0) <= demand);
        add_balance(v, -demand);
    }

    Cap balance(int v) const {
        assert(0 <= v && v < _n);
        return _balance[v];
    }

    const std::vector<Cap>& balances() const {
        return _balance;
    }

    std::optional<Result> min_cost_flow() const {
        return min_cost_flow(_balance);
    }

    std::optional<Result> min_cost_flow(const std::vector<Cap>& balance) const {
        assert(int(balance.size()) == _n);
        Cap balance_sum = Cap(0);
        for (Cap value : balance) balance_sum += value;
        if (balance_sum != Cap(0)) return std::nullopt;

        NetworkSimplexSolver solver(_n, balance);
        solver.reserve_edges(int(_edges.size()));
        for (const auto& edge : _edges) {
            solver.add_edge(edge.from, edge.to, edge.lower, edge.upper, edge.cost);
        }
        const std::size_t graph_size =
            std::size_t(_n) + _edges.size() + 1;
        std::size_t pivot_limit = 0;
        if constexpr (PivotLimitFactor != 0) {
            const std::size_t maximum =
                std::numeric_limits<std::size_t>::max();
            pivot_limit = graph_size > maximum / PivotLimitFactor
                ? maximum : PivotLimitFactor * graph_size;
        }
        auto status = solver.solve(pivot_limit);
        if (status == NetworkSimplexSolver::Status::infeasible) {
            return std::nullopt;
        }
        if (status == NetworkSimplexSolver::Status::pivot_limit_reached) {
            return polynomial_min_cost_flow_impl(balance);
        }
        return make_result(balance, solver, std::move(solver.potential));
    }

    std::optional<Result> min_cost_flow_polynomial() const {
        return min_cost_flow_polynomial(_balance);
    }

    std::optional<Result> min_cost_flow_polynomial(
        const std::vector<Cap>& balance
    ) const {
        assert(int(balance.size()) == _n);
        Cap balance_sum = Cap(0);
        for (Cap value : balance) balance_sum += value;
        if (balance_sum != Cap(0)) return std::nullopt;
        return polynomial_min_cost_flow_impl(balance);
    }

    std::optional<Result> min_cost_st_flow(int s, int t, Cap flow_value) const {
        assert(0 <= s && s < _n);
        assert(0 <= t && t < _n);
        assert(s != t);
        std::vector<Cap> balance = _balance;
        balance[s] += flow_value;
        balance[t] -= flow_value;
        return min_cost_flow(balance);
    }

    std::optional<Result> min_cost_st_flow_polynomial(
        int s,
        int t,
        Cap flow_value
    ) const {
        assert(0 <= s && s < _n);
        assert(0 <= t && t < _n);
        assert(s != t);
        std::vector<Cap> balance = _balance;
        balance[s] += flow_value;
        balance[t] -= flow_value;
        return min_cost_flow_polynomial(balance);
    }
};

template <
    class Cap,
    class Cost,
    class TotalCost = Cost,
    std::size_t PivotLimitFactor = 8
>
using BMinCostFlow = BoundedMinCostFlow<
    Cap,
    Cost,
    TotalCost,
    PivotLimitFactor
>;

}  // namespace flow
}  // namespace m1une


#line 1 "graph/flow/gomory_hu.hpp"



#line 9 "graph/flow/gomory_hu.hpp"

namespace m1une {
namespace flow {

template <class Cap>
struct GomoryHu {
    struct Edge {
        int u;
        int v;
        Cap cap;
    };

   private:
    struct FlowEdge {
        int to;
        int rev;
        Cap cap;
        Cap initial_cap;
    };

    int _n;
    bool _built = false;
    std::vector<Edge> _edges;
    std::vector<Edge> _tree_edges;
    std::vector<int> _parent;
    std::vector<Cap> _cut_value;
    std::vector<std::vector<std::pair<int, Cap>>> _tree;
    std::vector<std::vector<int>> _up;
    std::vector<std::vector<Cap>> _minimum;
    std::vector<int> _depth;

    std::vector<std::vector<FlowEdge>> _graph;
    std::vector<Cap> _excess;
    std::vector<int> _height;
    std::vector<int> _height_count;
    std::vector<int> _current;
    std::vector<bool> _active;
    std::vector<std::vector<int>> _buckets;
    std::vector<int> _queue;
    int _highest;
    long long _work;
    long long _work_limit;

    void add_flow_edge(int u, int v, Cap cap) {
        if (u == v || cap == Cap(0)) return;
        int ui = int(_graph[u].size());
        int vi = int(_graph[v].size());
        _graph[u].push_back(FlowEdge{v, vi, cap, cap});
        _graph[v].push_back(FlowEdge{u, ui, cap, cap});
    }

    void reset_flow() {
        for (auto& edges : _graph) {
            for (auto& edge : edges) edge.cap = edge.initial_cap;
        }
    }

    void activate(int v, int s, int t) {
        int dead = 2 * _n;
        if (v == s || v == t || _active[v] || _excess[v] == Cap(0) || _height[v] >= dead) return;
        _active[v] = true;
        _buckets[_height[v]].push_back(v);
        _highest = std::max(_highest, _height[v]);
    }

    void rebuild_buckets(int s, int t) {
        for (auto& bucket : _buckets) bucket.clear();
        std::fill(_active.begin(), _active.end(), false);
        _highest = -1;
        for (int v = 0; v < _n; v++) activate(v, s, t);
    }

    void global_relabel(int s, int t) {
        int dead = 2 * _n;
        int unreachable = _n + 1;
        std::fill(_height.begin(), _height.end(), unreachable);
        std::fill(_height_count.begin(), _height_count.end(), 0);
        std::fill(_current.begin(), _current.end(), 0);

        int head = 0;
        int tail = 0;
        _height[t] = 0;
        _height[s] = _n;
        _queue[tail++] = t;
        while (head < tail) {
            int v = _queue[head++];
            for (const auto& edge : _graph[v]) {
                const FlowEdge& reverse = _graph[edge.to][edge.rev];
                if (reverse.cap == Cap(0) || _height[edge.to] != unreachable) continue;
                _height[edge.to] = _height[v] + 1;
                _queue[tail++] = edge.to;
            }
        }
        for (int v = 0; v < _n; v++) {
            _height[v] = std::min(_height[v], dead);
            _height_count[_height[v]]++;
        }
        rebuild_buckets(s, t);
        _work = 0;
    }

    void push(int v, FlowEdge& edge, int s, int t) {
        if (edge.cap == Cap(0) || _height[v] != _height[edge.to] + 1) return;
        Cap sent = std::min(_excess[v], edge.cap);
        if (sent == Cap(0)) return;
        bool was_zero = _excess[edge.to] == Cap(0);
        edge.cap -= sent;
        _graph[edge.to][edge.rev].cap += sent;
        _excess[v] -= sent;
        _excess[edge.to] += sent;
        if (was_zero) activate(edge.to, s, t);
    }

    void gap(int height, int s, int t) {
        int unreachable = _n + 1;
        for (int v = 0; v < _n; v++) {
            if (v == s || v == t || _height[v] <= height || _height[v] >= _n) continue;
            _height_count[_height[v]]--;
            _height[v] = unreachable;
            _height_count[_height[v]]++;
            _current[v] = 0;
        }
        rebuild_buckets(s, t);
    }

    bool relabel(int v, int s, int t) {
        int dead = 2 * _n;
        int old_height = _height[v];
        int new_height = dead;
        _work += int(_graph[v].size());
        for (const auto& edge : _graph[v]) {
            if (edge.cap != Cap(0)) new_height = std::min(new_height, _height[edge.to] + 1);
        }
        _height_count[old_height]--;
        _height[v] = std::min(new_height, dead);
        _height_count[_height[v]]++;
        _current[v] = 0;
        if (old_height < _n && _height_count[old_height] == 0) {
            gap(old_height, s, t);
            return true;
        }
        return false;
    }

    void discharge(int v, int s, int t) {
        while (_excess[v] != Cap(0) && _height[v] < 2 * _n) {
            if (_current[v] == int(_graph[v].size())) {
                if (relabel(v, s, t)) return;
                continue;
            }
            FlowEdge& edge = _graph[v][_current[v]];
            _work++;
            if (edge.cap != Cap(0) && _height[v] == _height[edge.to] + 1) {
                push(v, edge, s, t);
            } else {
                _current[v]++;
            }
        }
        activate(v, s, t);
    }

    Cap max_flow(int s, int t) {
        reset_flow();
        std::fill(_excess.begin(), _excess.end(), Cap(0));
        for (auto& edge : _graph[s]) {
            Cap sent = edge.cap;
            if (sent == Cap(0)) continue;
            edge.cap = Cap(0);
            _graph[edge.to][edge.rev].cap += sent;
            _excess[edge.to] += sent;
        }
        global_relabel(s, t);

        while (_highest >= 0) {
            if (_buckets[_highest].empty()) {
                _highest--;
                continue;
            }
            int v = _buckets[_highest].back();
            _buckets[_highest].pop_back();
            if (!_active[v] || _height[v] != _highest) continue;
            _active[v] = false;
            discharge(v, s, t);
            if (_work >= _work_limit) global_relabel(s, t);
        }
        return _excess[t];
    }

    std::vector<bool> source_side(int s) {
        std::vector<bool> visited(_n, false);
        int head = 0;
        int tail = 0;
        visited[s] = true;
        _queue[tail++] = s;
        while (head < tail) {
            int v = _queue[head++];
            for (const auto& edge : _graph[v]) {
                if (edge.cap == Cap(0) || visited[edge.to]) continue;
                visited[edge.to] = true;
                _queue[tail++] = edge.to;
            }
        }
        return visited;
    }

    void build_query_table() {
        int log = 1;
        while ((1LL << log) <= std::max(1, _n)) log++;
        const Cap infinity = std::numeric_limits<Cap>::max();
        _up.assign(log, std::vector<int>(_n, 0));
        _minimum.assign(log, std::vector<Cap>(_n, infinity));
        _depth.assign(_n, 0);
        if (_n == 0) return;

        std::vector<int> order;
        order.reserve(_n);
        order.push_back(0);
        for (int i = 0; i < int(order.size()); i++) {
            int v = order[i];
            for (auto [to, cap] : _tree[v]) {
                if (to == _up[0][v] && v != 0) continue;
                _up[0][to] = v;
                _minimum[0][to] = cap;
                _depth[to] = _depth[v] + 1;
                order.push_back(to);
            }
        }
        for (int k = 1; k < log; k++) {
            for (int v = 0; v < _n; v++) {
                int middle = _up[k - 1][v];
                _up[k][v] = _up[k - 1][middle];
                _minimum[k][v] = std::min(_minimum[k - 1][v], _minimum[k - 1][middle]);
            }
        }
    }

   public:
    GomoryHu() : GomoryHu(0) {}

    explicit GomoryHu(int n) : _n(n) {
        assert(0 <= n);
    }

    int size() const {
        return _n;
    }

    int edge_count() const {
        return int(_edges.size());
    }

    int add_edge(int u, int v, Cap cap) {
        assert(0 <= u && u < _n);
        assert(0 <= v && v < _n);
        assert(Cap(0) <= cap);
        _built = false;
        int id = int(_edges.size());
        _edges.push_back(Edge{u, v, cap});
        return id;
    }

    void build() {
        std::vector<Edge> flow_edges;
        flow_edges.reserve(_edges.size());
        for (auto edge : _edges) {
            if (edge.u == edge.v || edge.cap == Cap(0)) continue;
            if (edge.u > edge.v) std::swap(edge.u, edge.v);
            flow_edges.push_back(edge);
        }
        std::sort(flow_edges.begin(), flow_edges.end(), [](const Edge& lhs, const Edge& rhs) {
            return std::pair<int, int>(lhs.u, lhs.v) < std::pair<int, int>(rhs.u, rhs.v);
        });
        int unique_edges = 0;
        for (const auto& edge : flow_edges) {
            if (unique_edges > 0 && flow_edges[unique_edges - 1].u == edge.u &&
                flow_edges[unique_edges - 1].v == edge.v) {
                flow_edges[unique_edges - 1].cap += edge.cap;
            } else {
                flow_edges[unique_edges++] = edge;
            }
        }
        flow_edges.resize(unique_edges);

        _graph.assign(_n, {});
        std::vector<int> degree(_n, 0);
        for (const auto& edge : flow_edges) {
            degree[edge.u]++;
            degree[edge.v]++;
        }
        for (int v = 0; v < _n; v++) _graph[v].reserve(degree[v]);
        for (const auto& edge : flow_edges) add_flow_edge(edge.u, edge.v, edge.cap);
        _excess.resize(_n);
        _height.resize(_n);
        _height_count.resize(2 * _n + 1);
        _current.resize(_n);
        _active.resize(_n);
        _buckets.resize(2 * _n + 1);
        _queue.resize(_n);
        long long arc_count = 0;
        for (const auto& edges : _graph) arc_count += int(edges.size());
        _work_limit = std::max(1LL, 4 * arc_count + _n);

        _parent.assign(_n, 0);
        _cut_value.assign(_n, std::numeric_limits<Cap>::max());
        for (int s = 1; s < _n; s++) {
            int t = _parent[s];
            Cap flow = max_flow(s, t);
            std::vector<bool> cut = source_side(s);
            for (int v = s + 1; v < _n; v++) {
                if (_parent[v] == t && cut[v]) _parent[v] = s;
            }
            if (cut[_parent[t]]) {
                _parent[s] = _parent[t];
                _parent[t] = s;
                _cut_value[s] = _cut_value[t];
                _cut_value[t] = flow;
            } else {
                _cut_value[s] = flow;
            }
        }

        _tree.assign(_n, {});
        _tree_edges.clear();
        if (_n > 0) _tree_edges.reserve(_n - 1);
        for (int v = 1; v < _n; v++) {
            int p = _parent[v];
            Cap cap = _cut_value[v];
            _tree_edges.push_back(Edge{v, p, cap});
            _tree[v].emplace_back(p, cap);
            _tree[p].emplace_back(v, cap);
        }
        build_query_table();
        _built = true;
    }

    const std::vector<Edge>& tree_edges() const {
        assert(_built);
        return _tree_edges;
    }

    const std::vector<int>& parent() const {
        assert(_built);
        return _parent;
    }

    const std::vector<Cap>& cut_values() const {
        assert(_built);
        return _cut_value;
    }

    Cap min_cut(int u, int v) const {
        assert(_built);
        assert(0 <= u && u < _n);
        assert(0 <= v && v < _n);
        assert(u != v);
        Cap result = std::numeric_limits<Cap>::max();
        if (_depth[u] < _depth[v]) std::swap(u, v);
        int difference = _depth[u] - _depth[v];
        for (int k = 0; difference > 0; k++, difference >>= 1) {
            if ((difference & 1) == 0) continue;
            result = std::min(result, _minimum[k][u]);
            u = _up[k][u];
        }
        if (u == v) return result;
        for (int k = int(_up.size()) - 1; k >= 0; k--) {
            if (_up[k][u] == _up[k][v]) continue;
            result = std::min(result, _minimum[k][u]);
            result = std::min(result, _minimum[k][v]);
            u = _up[k][u];
            v = _up[k][v];
        }
        result = std::min(result, _minimum[0][u]);
        result = std::min(result, _minimum[0][v]);
        return result;
    }
};

}  // namespace flow
}  // namespace m1une


#line 1 "graph/flow/min_cost_flow.hpp"



#line 5 "graph/flow/min_cost_flow.hpp"
#include <array>
#include <bit>
#line 12 "graph/flow/min_cost_flow.hpp"
#include <type_traits>
#line 15 "graph/flow/min_cost_flow.hpp"

#line 18 "graph/flow/min_cost_flow.hpp"

namespace m1une {
namespace flow {

template <class Cap, class Cost>
struct MinCostFlow {
    struct Edge {
        int from;
        int to;
        Cap cap;
        Cap flow;
        Cost cost;
    };

   private:
    struct InternalEdge {
        int to;
        int rev;
        Cap cap;
        Cost cost;
    };

    int _n;
    std::vector<std::pair<int, int>> _pos;
    std::vector<std::vector<InternalEdge>> _g;
    bool _has_negative_cost;
    bool _has_flow;

    template <class Key>
    struct RadixHeap {
        using Unsigned = std::make_unsigned_t<Key>;
        static constexpr int bits = std::numeric_limits<Unsigned>::digits;

        std::array<std::vector<std::pair<Unsigned, int>>, bits + 1> bucket;
        Unsigned last = 0;
        std::size_t count = 0;

        static int index(Unsigned first, Unsigned second) {
            return int(std::bit_width(first ^ second));
        }

        void clear() {
            for (auto& values : bucket) values.clear();
            last = 0;
            count = 0;
        }

        bool empty() const {
            return count == 0;
        }

        void push(Key key, int vertex) {
            Unsigned value = static_cast<Unsigned>(key);
            assert(last <= value);
            bucket[index(value, last)].emplace_back(value, vertex);
            count++;
        }

        std::pair<Key, int> pop() {
            if (bucket[0].empty()) {
                int i = 1;
                while (bucket[i].empty()) i++;
                last = bucket[i][0].first;
                for (const auto& value : bucket[i]) {
                    last = std::min(last, value.first);
                }
                for (const auto& value : bucket[i]) {
                    bucket[index(value.first, last)].push_back(value);
                }
                bucket[i].clear();
            }
            auto [key, vertex] = bucket[0].back();
            bucket[0].pop_back();
            count--;
            return {static_cast<Key>(key), vertex};
        }
    };

    template <class Key>
    struct BinaryHeap {
        using Value = std::pair<Key, int>;
        std::vector<Value> heap;

        void clear() {
            heap.clear();
        }

        bool empty() const {
            return heap.empty();
        }

        void push(Key key, int vertex) {
            heap.emplace_back(key, vertex);
            std::push_heap(heap.begin(), heap.end(), std::greater<Value>());
        }

        Value pop() {
            std::pop_heap(heap.begin(), heap.end(), std::greater<Value>());
            Value result = heap.back();
            heap.pop_back();
            return result;
        }
    };

    template <
        class Key,
        bool UseRadix =
            std::numeric_limits<Key>::is_integer && sizeof(Key) <= 8
    >
    struct HeapSelector {
        using Type = BinaryHeap<Key>;
    };

    template <class Key>
    struct HeapSelector<Key, true> {
        using Type = RadixHeap<Key>;
    };

    bool use_network_simplex(int s, int t, Cap flow_limit) const {
        if (_has_negative_cost) return false;
        if (_pos.size() < 64) return false;
        auto add_saturated = [](Cap first, Cap second) {
            const Cap maximum = std::numeric_limits<Cap>::max();
            return maximum - first < second ? maximum : first + second;
        };
        struct TerminalCapacity {
            Cap total = Cap(0);
            std::array<Cap, 7> largest{};
        };
        auto add_capacity = [&](TerminalCapacity& terminal, Cap cap) {
            terminal.total = add_saturated(terminal.total, cap);
            for (Cap& current : terminal.largest) {
                if (cap <= current) break;
                std::swap(cap, current);
            }
        };
        TerminalCapacity source;
        for (const auto& e : _g[s]) {
            if (e.to == s) continue;
            add_capacity(source, e.cap);
        }
        TerminalCapacity sink;
        for (const auto& e : _g[t]) {
            if (e.to == t) continue;
            Cap cap = _g[e.to][e.rev].cap;
            add_capacity(sink, cap);
        }
        Cap target = std::min(
            flow_limit,
            std::min(source.total, sink.total)
        );
        if (target == Cap(0)) return false;
        auto requires_eight_arcs = [&](const TerminalCapacity& terminal) {
            Cap sum = Cap(0);
            for (Cap cap : terminal.largest) {
                sum = add_saturated(sum, cap);
            }
            return sum < target;
        };
        return requires_eight_arcs(source) && requires_eight_arcs(sink);
    }

    std::pair<Cap, Cost> network_simplex_flow(
        int s,
        int t,
        Cap flow_limit
    ) {
        struct ResidualArc {
            int edge;
            bool reverse;
        };

        using Solver = BoundedMinCostFlow<Cap, Cost, Cost>;
        std::vector<ResidualArc> arcs;
        arcs.reserve(2 * _pos.size());
        for (int i = 0; i < int(_pos.size()); i++) {
            auto [from, idx] = _pos[i];
            const auto& e = _g[from][idx];
            const auto& reverse = _g[e.to][e.rev];
            if (e.cap != Cap(0)) {
                arcs.push_back(ResidualArc{i, false});
            }
            if (reverse.cap != Cap(0)) {
                arcs.push_back(ResidualArc{i, true});
            }
        }

        auto add_saturated = [](Cap first, Cap second, bool& exact) {
            const Cap maximum = std::numeric_limits<Cap>::max();
            if (maximum - first < second) {
                exact = false;
                return maximum;
            }
            return first + second;
        };
        bool source_capacity_exact = true;
        Cap source_capacity = Cap(0);
        for (const auto& e : _g[s]) {
            if (e.to == s) continue;
            source_capacity = add_saturated(
                source_capacity,
                e.cap,
                source_capacity_exact
            );
        }
        bool sink_capacity_exact = true;
        Cap sink_capacity = Cap(0);
        for (const auto& e : _g[t]) {
            if (e.to == t) continue;
            sink_capacity = add_saturated(
                sink_capacity,
                _g[e.to][e.rev].cap,
                sink_capacity_exact
            );
        }
        Cap target = std::min(
            flow_limit,
            std::min(source_capacity, sink_capacity)
        );
        if (target == Cap(0)) return {Cap(0), Cost(0)};

        struct ArcData {
            int from;
            int to;
            Cap cap;
            Cost cost;
        };
        auto arc_data = [&](const ResidualArc& arc) {
            auto [from, idx] = _pos[arc.edge];
            const auto& e = _g[from][idx];
            const auto& reverse = _g[e.to][e.rev];
            return arc.reverse
                ? ArcData{e.to, from, reverse.cap, reverse.cost}
                : ArcData{from, e.to, e.cap, e.cost};
        };
        auto apply_flow = [&](const ResidualArc& arc, Cap amount) {
            auto [from, idx] = _pos[arc.edge];
            auto& e = _g[from][idx];
            auto& reverse = _g[e.to][e.rev];
            if (arc.reverse) {
                reverse.cap -= amount;
                e.cap += amount;
            } else {
                e.cap -= amount;
                reverse.cap += amount;
            }
        };

        bool target_infeasible = false;
        if (
            source_capacity_exact && sink_capacity_exact &&
            target == source_capacity && target == sink_capacity
        ) {
            Solver terminal_solver(_n);
            terminal_solver.reserve_edges(int(arcs.size()));
            std::vector<Cap> balance(_n, Cap(0));
            std::vector<int> internal_arcs;
            std::vector<int> fixed_arcs;
            internal_arcs.reserve(arcs.size());
            fixed_arcs.reserve(_g[s].size() + _g[t].size());
            Cost fixed_cost = Cost(0);
            for (int i = 0; i < int(arcs.size()); i++) {
                ArcData data = arc_data(arcs[i]);
                if (data.from == s) {
                    if (data.to == s) continue;
                    fixed_arcs.push_back(i);
                    fixed_cost += Cost(data.cap) * data.cost;
                    if (data.to != t) balance[data.to] += data.cap;
                } else if (data.to == t) {
                    if (data.from == t) continue;
                    fixed_arcs.push_back(i);
                    fixed_cost += Cost(data.cap) * data.cost;
                    balance[data.from] -= data.cap;
                } else if (data.to != s && data.from != t) {
                    terminal_solver.add_edge(
                        data.from,
                        data.to,
                        Cap(0),
                        data.cap,
                        data.cost
                    );
                    internal_arcs.push_back(i);
                }
            }
            auto terminal_result = terminal_solver.min_cost_flow(balance);
            if (terminal_result) {
                for (int i : fixed_arcs) {
                    apply_flow(arcs[i], arc_data(arcs[i]).cap);
                }
                for (int i = 0; i < int(internal_arcs.size()); i++) {
                    apply_flow(
                        arcs[internal_arcs[i]],
                        terminal_result->flow(i)
                    );
                }
                _has_flow = true;
                return {target, fixed_cost + terminal_result->cost};
            }
            target_infeasible = true;
        }

        Solver solver(_n);
        solver.reserve_edges(int(arcs.size()));
        for (const auto& arc : arcs) {
            ArcData data = arc_data(arc);
            solver.add_edge(
                data.from,
                data.to,
                Cap(0),
                data.cap,
                data.cost
            );
        }
        Cap sent = target;
        std::optional<typename Solver::Result> result;
        if (
            !target_infeasible &&
            target != std::numeric_limits<Cap>::max()
        ) {
            result = solver.min_cost_st_flow(s, t, target);
        }
        if (!result) {
            MaxFlow<Cap> feasible(_n);
            feasible.reserve_edges(int(arcs.size()));
            for (const auto& arc : arcs) {
                auto [from, idx] = _pos[arc.edge];
                const auto& e = _g[from][idx];
                const auto& reverse = _g[e.to][e.rev];
                if (arc.reverse) {
                    feasible.add_edge(e.to, from, reverse.cap);
                } else {
                    feasible.add_edge(from, e.to, e.cap);
                }
            }
            sent = feasible.max_flow(s, t, target);
            if (sent == Cap(0)) return {Cap(0), Cost(0)};
            result = solver.min_cost_st_flow(s, t, sent);
        }
        assert(result.has_value());
        for (int i = 0; i < int(arcs.size()); i++) {
            auto [from, idx] = _pos[arcs[i].edge];
            auto& e = _g[from][idx];
            auto& reverse = _g[e.to][e.rev];
            Cap amount = result->flow(i);
            if (arcs[i].reverse) {
                reverse.cap -= amount;
                e.cap += amount;
            } else {
                e.cap -= amount;
                reverse.cap += amount;
            }
        }
        _has_flow = true;
        return {sent, result->cost};
    }

    void init_potential(int s, std::vector<Cost>& potential, Cost cost_inf) const {
        if (!_has_negative_cost && !_has_flow) {
            potential.assign(_n, Cost(0));
            return;
        }
        potential.assign(_n, cost_inf);
        potential[s] = Cost(0);
        for (int iter = 0; iter < _n - 1; iter++) {
            bool updated = false;
            for (int v = 0; v < _n; v++) {
                if (potential[v] == cost_inf) continue;
                for (const auto& e : _g[v]) {
                    if (e.cap == Cap(0)) continue;
                    Cost nd = potential[v] + e.cost;
                    if (nd < potential[e.to]) {
                        potential[e.to] = nd;
                        updated = true;
                    }
                }
            }
            if (!updated) break;
        }
        for (int v = 0; v < _n; v++) {
            if (potential[v] == cost_inf) potential[v] = Cost(0);
        }
    }

   public:
    MinCostFlow() : MinCostFlow(0) {}

    explicit MinCostFlow(int n)
        : _n(n), _g(n), _has_negative_cost(false), _has_flow(false) {
        assert(0 <= n);
    }

    int size() const {
        return _n;
    }

    int edge_count() const {
        return int(_pos.size());
    }

    void reserve_edges(int edge_count) {
        assert(0 <= edge_count);
        _pos.reserve(edge_count);
        if (_n == 0 || edge_count == 0 ||
            2 * std::size_t(edge_count) < std::size_t(_n)) {
            return;
        }
        const std::size_t average_degree =
            (3 * std::size_t(edge_count) + std::size_t(_n) - 1)
            / std::size_t(_n);
        for (auto& edges : _g) edges.reserve(average_degree);
    }

    void reserve_edges(int edge_count, const std::vector<int>& degrees) {
        assert(0 <= edge_count);
        assert(int(degrees.size()) == _n);
        _pos.reserve(edge_count);
        for (int v = 0; v < _n; v++) {
            assert(0 <= degrees[v]);
            _g[v].reserve(degrees[v]);
        }
    }

    int add_edge(int from, int to, Cap cap, Cost cost) {
        assert(0 <= from && from < _n);
        assert(0 <= to && to < _n);
        assert(Cap(0) <= cap);
        _has_negative_cost = _has_negative_cost || cost < Cost(0);
        int id = int(_pos.size());
        int from_id = int(_g[from].size());
        int to_id = int(_g[to].size());
        if (from == to) to_id++;
        _pos.emplace_back(from, from_id);
        _g[from].push_back(InternalEdge{to, to_id, cap, cost});
        _g[to].push_back(InternalEdge{from, from_id, Cap(0), -cost});
        return id;
    }

    Edge get_edge(int i) const {
        assert(0 <= i && i < int(_pos.size()));
        auto [from, idx] = _pos[i];
        const auto& e = _g[from][idx];
        const auto& re = _g[e.to][e.rev];
        return Edge{from, e.to, e.cap + re.cap, re.cap, e.cost};
    }

    std::vector<Edge> edges() const {
        std::vector<Edge> result;
        result.reserve(_pos.size());
        for (int i = 0; i < int(_pos.size()); i++) result.push_back(get_edge(i));
        return result;
    }

    std::pair<Cap, Cost> flow(int s, int t) {
        return flow(s, t, std::numeric_limits<Cap>::max());
    }

    std::pair<Cap, Cost> flow(int s, int t, Cap flow_limit) {
        assert(0 <= s && s < _n);
        assert(0 <= t && t < _n);
        assert(s != t);
        assert(Cap(0) <= flow_limit);
        if (flow_limit == Cap(0)) return {Cap(0), Cost(0)};
        if constexpr (
            std::numeric_limits<Cap>::is_integer &&
            std::numeric_limits<Cap>::is_signed &&
            std::numeric_limits<Cost>::is_signed
        ) {
            if (use_network_simplex(s, t, flow_limit)) {
                return network_simplex_flow(s, t, flow_limit);
            }
        }
        auto result = slope(s, t, flow_limit);
        return result.back();
    }

    std::vector<std::pair<Cap, Cost>> slope(int s, int t) {
        return slope(s, t, std::numeric_limits<Cap>::max());
    }

    std::vector<std::pair<Cap, Cost>> slope(int s, int t, Cap flow_limit) {
        assert(0 <= s && s < _n);
        assert(0 <= t && t < _n);
        assert(s != t);
        assert(Cap(0) <= flow_limit);

        const Cost cost_inf = std::numeric_limits<Cost>::max() / Cost(4);
        std::vector<Cost> potential, dist(_n);
        std::vector<int> prev_v(_n), prev_e(_n);
        std::vector<int> settled;
        settled.reserve(_n);
        typename HeapSelector<Cost>::Type que;
        init_potential(s, potential, cost_inf);

        std::vector<std::pair<Cap, Cost>> result;
        result.emplace_back(Cap(0), Cost(0));
        Cap flow = 0;
        Cost cost = 0;

        while (flow < flow_limit) {
            std::fill(dist.begin(), dist.end(), cost_inf);
            dist[s] = Cost(0);
            settled.clear();
            que.clear();
            que.push(Cost(0), s);

            while (!que.empty()) {
                auto [d, v] = que.pop();
                if (dist[v] != d) continue;
                settled.push_back(v);
                if (v == t) break;
                for (int i = 0; i < int(_g[v].size()); i++) {
                    const auto& e = _g[v][i];
                    if (e.cap == Cap(0)) continue;
                    Cost nd = d + e.cost + potential[v] - potential[e.to];
                    if (nd >= dist[e.to]) continue;
                    dist[e.to] = nd;
                    prev_v[e.to] = v;
                    prev_e[e.to] = i;
                    que.push(nd, e.to);
                }
            }

            if (dist[t] == cost_inf) break;
            for (int v : settled) {
                potential[v] += dist[v] - dist[t];
            }

            Cap add = flow_limit - flow;
            for (int v = t; v != s; v = prev_v[v]) {
                add = std::min(add, _g[prev_v[v]][prev_e[v]].cap);
            }
            Cost path_cost = potential[t] - potential[s];
            for (int v = t; v != s; v = prev_v[v]) {
                auto& e = _g[prev_v[v]][prev_e[v]];
                e.cap -= add;
                _g[e.to][e.rev].cap += add;
            }

            flow += add;
            cost += Cost(add) * path_cost;
            result.emplace_back(flow, cost);
        }

        _has_flow = _has_flow || flow != Cap(0);
        return result;
    }
};

}  // namespace flow
}  // namespace m1une


#line 9 "graph/flow/flow.hpp"
Back to top page