Cod sursa(job #1996633)

Utilizator bciobanuBogdan Ciobanu bciobanu Data 2 iulie 2017 09:54:17
Problema Flux maxim Scor 20
Compilator cpp Status done
Runda Arhiva educationala Marime 11.73 kb
#include <fstream>
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

struct Edge {
    int from;
    int to;
    int capacity;
    int flow;
    Edge(int from, int to, int capacity, int flow) :
            from(from), to(to), capacity(capacity), flow(flow) {}
};

struct Node {
    static constexpr uint32_t null = uint32_t(-1);
    uint32_t left = null;
    uint32_t right = null;
    uint32_t parent = null;
    int dv;
    int min;
    Node() : dv(0), min(0) {}
    Node(int value) : dv(value), min(0) {}
};

template<class E, bool oriented = false>
struct DynamicTree {
    static int capacity(int v, E* edge) {
        if (edge->from == v) {
            return edge->capacity - edge->flow;
        } else {
            return oriented ? edge->flow : edge->flow + edge->capacity;
        }
    }

    static void setCapacity(int v, E* edge, int cap) {
        if (edge->from == v) {
            edge->flow = edge->capacity - cap;
        } else {
            edge->flow = oriented ? cap : cap - edge->capacity;
        }
    }

    std::vector<E*> parentEdges;
    std::vector<Node> nodes;

    bool isRoot(uint32_t node) {
        uint32_t parent = nodes[node].parent;
        return parent == Node::null || (nodes[parent].left != node && nodes[parent].right != node);
    }

    void fixMin(uint32_t node) {
        int result = 0;
        uint32_t left = nodes[node].left;
        if (left != Node::null) {
            result = std::min(result, nodes[left].min + nodes[left].dv);
        }
        uint32_t right = nodes[node].right;
        if (right != Node::null) {
            result = std::min(result, nodes[right].min + nodes[right].dv);
        }
        nodes[node].min = result;
    }

    void rotate(uint32_t node) {
        uint32_t parent = nodes[node].parent;
        uint32_t middle;
        if (nodes[parent].left == node) {
            middle = nodes[node].right;
            nodes[node].right = parent;
            nodes[parent].left = middle;
        } else {
            middle = nodes[node].left;
            nodes[node].left = parent;
            nodes[parent].right = middle;
        }
        nodes[node].parent = nodes[parent].parent;
        uint32_t grandparent = nodes[node].parent;
        if (grandparent != Node::null) {
            if (nodes[grandparent].left == parent) {
                nodes[grandparent].left = node;
            } else if (nodes[grandparent].right == parent) {
                nodes[grandparent].right = node;
            }
        }
        nodes[parent].parent = node;
        int dNode = nodes[node].dv;
        int dParent = nodes[parent].dv;
        nodes[node].dv += dParent;
        nodes[parent].dv = -dNode;
        if (middle != Node::null) {
            nodes[middle].dv += dNode;
            nodes[middle].parent = parent;
        }
        fixMin(parent);
        fixMin(node);
    }

    void splay(uint32_t node) {
        while (!isRoot(node)) {
            uint32_t parent = nodes[node].parent;
            if (isRoot(parent)) {
                rotate(node);
                return;
            }
            uint32_t grandParent = nodes[parent].parent;
            if ((nodes[parent].left == node) == (nodes[grandParent].left == parent)) {
                rotate(parent);
            } else {
                rotate(node);
            }
            rotate(node);
        }
    }

    uint32_t pathRoot(uint32_t node) {
        while (true) {
            uint32_t right = nodes[node].right;
            if (right == Node::null) return node;
            node = right;
        }
    }

    void expose(uint32_t node) {
        splay(node);
        while (true) {
            uint32_t parent = nodes[node].parent;
            if (parent == Node::null) break;
            splay(parent);
            uint32_t left = nodes[parent].left;
            if (left != Node::null) {
                nodes[left].dv += nodes[parent].dv;
            }
            if (nodes[parent].parent == Node::null && nodes[parent].right == Node::null) {
                nodes[parent].dv = std::numeric_limits<int>::max();
                nodes[parent].min = 0;
            }
            nodes[parent].left = node;
            nodes[node].dv -= nodes[parent].dv;
            // fixMin(parent); // fixed by rotate
            rotate(node);
        }
    }

    uint32_t getRoot(uint32_t node) {
        expose(node);
        return pathRoot(node);
    }

    uint32_t disconnectRoot(uint32_t root) {
        uint32_t newRoot = root;
        if (nodes[newRoot].left == Node::null) {
            newRoot = nodes[newRoot].parent;
        } else {
            newRoot = nodes[newRoot].left;
            while (nodes[newRoot].right != Node::null) {
                newRoot = nodes[newRoot].right;
            }
        }
        splay(newRoot);
        nodes[newRoot].parent = Node::null;
        nodes[newRoot].right = Node::null;
        nodes[root].parent = Node::null;
        nodes[root].dv = std::numeric_limits<int>::max();
        nodes[root].min = 0;
        setCapacity(newRoot, parentEdges[newRoot], nodes[newRoot].dv);
        parentEdges[newRoot] = nullptr;
        if (nodes[newRoot].left != Node::null) {
            nodes[nodes[newRoot].left].dv += nodes[newRoot].dv - std::numeric_limits<int>::max();
        }
        nodes[newRoot].dv = std::numeric_limits<int>::max();
        nodes[newRoot].min = 0;
        return newRoot;
    }

    void disconnectVertex(uint32_t u) {
        splay(u);
        uint32_t v = nodes[u].right;
        nodes[u].right = Node::null;
        nodes[v].dv += nodes[u].dv;
        nodes[v].parent = nodes[u].parent;
        nodes[u].parent = Node::null;

        setCapacity(u, parentEdges[u], nodes[u].dv);
        if (nodes[u].left != Node::null) {
            nodes[nodes[u].left].dv += nodes[u].dv - std::numeric_limits<int>::max();
        }
        nodes[u].dv = std::numeric_limits<int>::max();
        parentEdges[u] = nullptr;
        nodes[u].min = 0;
        if (nodes[v].left == Node::null && nodes[v].right == Node::null) {
            nodes[v].dv = std::numeric_limits<int>::max();
            nodes[v].min = 0;
        }
    }

    void link(uint32_t u, uint32_t v, Edge* edge) {
        splay(u);
        int cap = capacity(u, edge);
        int delta = cap - nodes[u].dv;
        nodes[u].dv = cap;
        if (nodes[u].left != Node::null) {
            nodes[nodes[u].left].dv -= delta;
        }
        fixMin(u);
        parentEdges[u] = edge;
        nodes[u].parent = v;
    }

    int getPathMin(uint32_t u) {
        splay(u);
        return nodes[u].min + nodes[u].dv;
    }

    void subtractPath(uint32_t u, int value) {
        splay(u);
        nodes[u].dv -= value;
        if (nodes[u].left != Node::null) {
            nodes[nodes[u].left].dv += value;
        }
        fixMin(u);
    }

    uint32_t findNonZeroPath(uint32_t u) {
        splay(u);
        int delta = nodes[u].dv;
        if (delta == 0) return u;
        uint32_t check = nodes[u].right;
        while (true) {
            delta += nodes[check].dv;
            uint32_t left = nodes[check].left;
            if (left == Node::null || delta + nodes[left].dv + nodes[left].min > 0) {
                if (delta == 0) {
                    return check;
                }
                check = nodes[check].right;
                continue;
            }
            check = left;
        }
    }

    void destroy(uint32_t v, int value) {
        value += nodes[v].dv;
        if (parentEdges[v] != nullptr) {
            setCapacity(v, parentEdges[v], value);
            parentEdges[v] = nullptr;
        }
        if (nodes[v].left != Node::null) {
            destroy(nodes[v].left, value);
        }
        if (nodes[v].right != Node::null) {
            destroy(nodes[v].right, value);
        }
    }

    void destroyAll() {
        for (uint32_t i = 0; i < nodes.size(); i++) {
            if (isRoot(i)) {
                destroy(i, 0);
            }
        }
    }

};

template<class E, bool oriented = false>
struct Flow2 {
    std::vector<std::vector<E*>>* pGraph;
    int vFrom;
    int vTo;
    int n;
    std::vector<int> queue;
    std::vector<int> ranks;
    std::vector<int> edgeIdx;
    DynamicTree<E, oriented> tree;

    static int capacity(int v, E* edge) {
        if (edge->from == v) {
            return edge->capacity - edge->flow;
        } else {
            return oriented ? edge->flow : edge->flow + edge->capacity;
        }
    }

    static int other(int v, E* edge) {
        return edge->from ^ edge->to ^ v;
    }

    void calcRanks(int capacity_limit) {
        std::fill(ranks.begin(), ranks.end(), -1);
        int bque = 0;
        int eque = 1;
        queue[0] = vFrom;
        ranks[vFrom] = 0;
        while (eque > bque) {
            int v = queue[bque];
            bque++;
            int nr = ranks[v] + 1;
            for (auto edge : (*pGraph)[v]) {
                if (capacity(v, edge) > capacity_limit) {
                    int other = edge->from + edge->to - v;
                    if (ranks[other] < 0) {
                        queue[eque] = other;
                        eque++;
                        ranks[other] = nr;
                    }
                }
            }
            if (v == vTo) {
                break;
            }
        }
    }

    bool calcFlow(int capacity_limit) {
        bool found = false;
        auto& graph = *pGraph;
        int root = vFrom;
        while (root != vFrom || edgeIdx[root] != graph[root].size()) {
            if (root == vTo) {
                int cap = tree.getPathMin(vFrom);
                if (cap > capacity_limit) {
                    tree.subtractPath(vFrom, cap);
                    found = true;
                }
                root = tree.findNonZeroPath(vFrom);
                tree.disconnectVertex(root);
                continue;
            }
            if (edgeIdx[root] == graph[root].size()) {
                ranks[root] = -1;
            }
            if (ranks[root] < 0) {
                root = tree.disconnectRoot(root);
                continue;
            }
            auto edge = graph[root][edgeIdx[root]];
            int next = other(root, edge);
            if (ranks[next] != ranks[root] + 1) {
                edgeIdx[root]++;
                continue;
            }
            if (capacity(root, edge) <= capacity_limit) {
                edgeIdx[root]++;
                continue;
            }
            tree.link(root, next, edge);
            root = tree.getRoot(root);
        }
        tree.destroyAll();
        return found;
    }

    void solve(std::vector<std::vector<E*>>& graph, int from, int to, bool clear = true) {
        pGraph = &graph;
        vFrom = from;
        vTo = to;
        if (clear) {
            for (auto& vArray : graph) {
                for (auto& edge : vArray) {
                    edge->flow = 0;
                }
            }
        }
        n = graph.size();
        queue.resize(n);
        ranks.resize(n);
        edgeIdx.resize(n);
        for (int i = 31; i >= 0;) {
            calcRanks((1 << i) - 1);
            std::fill(edgeIdx.begin(), edgeIdx.end(), 0);
            tree.parentEdges.assign(n, nullptr);
            tree.nodes.assign(n, Node(std::numeric_limits<int>::max()));
            if (!calcFlow((1 << i) - 1)) {
                --i;
            }
        }
    }
};

int main() {
#ifdef INFOARENA
    ifstream cin("maxflow.in");
    ofstream cout("maxflow.out");
#endif
    int n, m;
    cin >> n >> m;
    vector<vector<Edge * >> graph(n);
    for (int i = 0; i < m; ++i) {
        int x, y, c;
        cin >> x >> y >> c;
        x--;
        y--;
        Edge *edge = new Edge(x, y, c, 0);
        graph[x].push_back(edge);
        graph[y].push_back(edge);
    }
    Flow2<Edge, true> flow;
    flow.solve(graph, 0, n - 1);
    int total = 0;
    for (const Edge *edge: graph[0]) {
        total += edge->flow;
    }
    cout << total << '\n';
}