Solution Set 2023.12.5

发布时间 2023-12-05 12:06:38作者: User-Unauthorized

[AHOI2009] 最小割

首先考虑如何处理可行边,对于边 \(\left(u, v\right)\),其为可行边与同时满足下列两个条件互为充要条件:

  • \(c_f(u, v) = 0\)
  • \(G_f\) 中不存在路径 \(u \rightarrow v\)

首先可以发现若存在 \(G_f\) 使得 \(c_f(u, v) > 0\),那么一定不会割这条边。

\(G_f\) 中存在路径 \(u \rightarrow v\),那么可以通过将边 \(\left(u, v\right)\) 的一小部分流量通过 \(G_f\) 中存在路径 \(u \rightarrow v\) 传递。这样之后有 \(c_f(u, v) > 0\),那么一定不会割这条边。

考虑在可行边的基础上添加什么条件才可以使得边为必须边。

可以发现,若对于可行边 \(\left(u, v\right)\),若在 \(G_f\) 上不存在路径使得 \(S \rightarrow u\),那么在 \(G\) 的任意一条路径 \(S \rightarrow u\) 上,均存在令一条可行边,因此边 \(\left(u, v\right)\) 不是必须边。

所以可行边 \(\left(u, v\right)\) 是必须边当且仅当 \(G_f\) 上存在路径 \(S \rightarrow u\) 和路径 \(v \rightarrow T\)

可以发现因为 \(c_f(u, v) = 0\),所以有 \(c_f(v, u) > 0\),即边 \(\left(v, u\right) \in G_f\),所以在 \(G_f\) 上存在路径 \(u \rightarrow v\) 等价于 \(u, v\)\(G_f\) 上位于同一个强连通分量中。同理 \(G_f\) 上存在路径 \(S \rightarrow u\) 和路径 \(v \rightarrow T\) 等价于 \(u\)\(S\) 在同一个强连通分量中且 \(v\)\(T\) 在同一个强连通分量中。

Code
#include <bits/stdc++.h>

typedef long long valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<bool> bitset;
typedef std::tuple<valueType, valueType, valueType> ValueTuple;
typedef std::vector<ValueTuple> TupleVector;

class Dinic {
private:
    struct Edge {
    public:
        typedef std::vector<Edge> container;
        typedef container::iterator iterator;

        valueType to;
        valueType cap;
        valueType flow;
        iterator pair;

        Edge() : to(-1), cap(-1), flow(-1), pair(){};

        Edge(valueType to, valueType cap, iterator pair = iterator()) : to(to), cap(cap), flow(0), pair(pair){};

        bool full() const {
            return flow == cap;
        }
    };

    typedef std::vector<ValueVector> Graph;
    typedef std::vector<ValueVector::iterator> IterVector;

    valueType N, M;
    Edge::container edges;
    Graph G;
    ValueVector depth;
    IterVector start;
    ValueVector belong;
    bitset inStack;
    ValueVector dfn, low;
    std::stack<valueType> stack;
    bool Initialized;

public:
    explicit Dinic(valueType N, valueType M) : N(N), M(M), edges((M << 1) + 10), G(N + 1), depth(N + 1, 0), start(N + 1), belong(N + 1, 0), inStack(N + 1, false), dfn(N + 1, 0), low(N + 1, 0), Initialized(false){};

    void addEdge(valueType from, valueType to, valueType cap, valueType id) {
        if (__builtin_expect(Initialized, false))
            throw std::runtime_error("Dinic: addEdge after init");

        edges[id << 1] = Edge(to, cap, std::next(edges.begin(), id << 1 | 1));
        edges[id << 1 | 1] = Edge(from, 0, std::next(edges.begin(), id << 1));
        G[from].emplace_back(id << 1);
        G[to].emplace_back(id << 1 | 1);
    }

    void init() {
        if (__builtin_expect(Initialized, false))
            throw std::runtime_error("Dinic: init twice");

        Initialized = true;

        std::fill(depth.begin(), depth.end(), 0);

        for (valueType i = 1; i <= N; ++i)
            start[i] = G[i].begin();
    }

    void reset() {
        if (__builtin_expect(!Initialized, false))
            throw std::runtime_error("Dinic: reset before init");

        for (valueType i = 1; i <= N; ++i)
            for (auto &iter : G[i])
                edges[iter].flow = 0;

        std::fill(depth.begin(), depth.end(), 0);

        Initialized = false;
    }

    valueType maxFlow(valueType S, valueType T) {
        if (__builtin_expect(!Initialized, false))
            throw std::runtime_error("Dinic: maxFlow before init");

        valueType result = 0;

        while (bfs(S, T)) {
            IterVector begin = start;

            result += dfs(S, T, std::numeric_limits<valueType>::max(), begin);
        }

        for (valueType i = 1; i <= N; ++i)
            if (!dfn[i])
                tarjan(i);

        return result;
    }

    valueType scc(valueType n) const {
        return belong[n];
    }

    bool full(valueType m) const {
        return edges[m].full();
    }

private:
    bool bfs(valueType S, valueType T) {
        std::fill(depth.begin(), depth.end(), 0);

        std::queue<valueType> Q;

        Q.push(S);
        depth[S] = 1;

        while (!Q.empty()) {
            valueType const u = Q.front();

            Q.pop();

            for (auto const &iter : G[u]) {
                auto const &e = edges[iter];
                if ((e.cap > e.flow) && (!depth[e.to])) {
                    depth[e.to] = depth[u] + 1;
                    Q.push(e.to);
                }
            }
        }

        return depth[T] > 0;
    }

    valueType dfs(valueType u, valueType T, valueType flow, IterVector &Begin) {
        if (u == T || flow == 0)
            return flow;

        valueType result = 0;

        for (auto &iter = Begin[u]; iter != G[u].end(); ++iter) {
            auto e = std::next(edges.begin(), *iter);
            if (e->cap > e->flow && depth[e->to] == depth[u] + 1) {
                valueType const f = dfs(e->to, T, std::min(flow - result, e->cap - e->flow), Begin);

                e->flow += f;
                e->pair->flow -= f;

                result += f;

                if (result == flow)
                    return flow;
            }
        }

        return result;
    }

    void tarjan(valueType x) {
        static valueType dfsCount = 0, sccCount = 0;

        inStack[x] = true;
        low[x] = dfn[x] = ++dfsCount;
        stack.push(x);

        for (auto const &iter : G[x]) {
            auto e = std::next(edges.begin(), iter);

            if (e->full())
                continue;

            if (!dfn[e->to]) {
                tarjan(e->to);

                low[x] = std::min(low[x], low[e->to]);
            } else if (inStack[e->to]) {
                low[x] = std::min(low[x], dfn[e->to]);
            }
        }

        if (dfn[x] == low[x]) {
            ++sccCount;

            valueType y;

            do {
                y = stack.top();

                stack.pop();

                inStack[y] = false;

                belong[y] = sccCount;
            } while (y != x);
        }
    }
};

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

    valueType N, M, S, T;

    std::cin >> N >> M >> S >> T;

    Dinic dinic(N, M);

    TupleVector G;

    G.reserve(M);

    for (valueType i = 1; i <= M; ++i) {
        valueType u, v, w;

        std::cin >> u >> v >> w;

        G.emplace_back(u, v, w);

        dinic.addEdge(u, v, w, i);
    }

    dinic.init();

    dinic.maxFlow(S, T);

    for (valueType i = 0; i < M; ++i) {
        valueType const id = i + 1;

        auto const &[u, v, w] = G[i];

        bool A = dinic.full(id << 1) && dinic.scc(u) != dinic.scc(v);

        bool B = A && dinic.scc(S) == dinic.scc(u) && dinic.scc(T) == dinic.scc(v);

        std::cout << A << ' ' << B << '\n';
    }

    std::cout << std::flush;

    return 0;
}