Solution Set【2023.12.7】

方格取数问题 / 王者之剑

可以发现,相互限制的格子的横纵坐标之和肯定是一个奇数和一个偶数。即横纵坐标之和奇偶性相同的格子之间一定不会限制。因此若我们将限制关系以边的形式表达,那么形成的图为一个二分图。

考虑令横纵坐标之和为奇数的格子为左部点,偶数的为右部点;分别对应 \(S, T\) 集合。令左部点不在 \(S\) 集合中表示不选择,右部点不在 \(T\) 集合中表示不选择。

那么对于一对限制的格子,可以考虑从横纵坐标之和为奇数的格子向横纵坐标之和为偶数的格子连一条容量为 \(\infty\) 的边。

那么也就是说源点连向奇数的格子的边和偶数的格子连向汇点的边中一定有一条被割掉,即两个格子不会同时选择,限制成立,求最小割即可。

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

typedef long long valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;

class Dinic {
private:
    struct Edge {
    public:
        typedef std::list<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){};
    };

    typedef std::vector<Edge::container> Graph;
    typedef std::vector<Edge::iterator> IterVector;

    valueType N;
    Graph G;
    ValueVector depth;
    IterVector start;
    bool Initialized;

public:
    explicit Dinic(valueType N) : N(N), G(N + 1), depth(N + 1, 0), start(N + 1), Initialized(false){};

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

        G[from].emplace_back(to, cap);
        G[to].emplace_back(from, 0);
        G[from].back().pair = std::prev(G[to].end());
        G[to].back().pair = std::prev(G[from].end());
    }

    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])
                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);
        }

        return result;
    }

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 &e : G[u]) {
                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 &e = Begin[u]; e != G[u].end(); ++e) {
            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;
    }
};

constexpr valueType INF = std::numeric_limits<valueType>::max();

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

    valueType N, M;

    std::cin >> N >> M;

    valueType size = 0;

    valueType const S = ++size, T = ++size;

    ValueMatrix ID(N + 1, ValueVector(M + 1, 0));

    for (valueType i = 1; i <= N; ++i)
        for (valueType j = 1; j <= M; ++j)
            ID[i][j] = ++size;

    Dinic dinic(size);

    valueType sum = 0;

    for (valueType i = 1; i <= N; ++i) {
        for (valueType j = 1; j <= M; ++j) {
            valueType weight;

            std::cin >> weight;

            sum += weight;

            if (((i + j) & 1) == 1) {
                dinic.addEdge(S, ID[i][j], weight);
            } else {
                dinic.addEdge(ID[i][j], T, weight);
            }
        }
    }

    for (valueType i = 1; i <= N; ++i) {
        for (valueType j = 1; j <= M; ++j) {
            if (((i + j) & 1) == 0)
                continue;

            if (i > 1)
                dinic.addEdge(ID[i][j], ID[i - 1][j], INF);

            if (i < N)
                dinic.addEdge(ID[i][j], ID[i + 1][j], INF);

            if (j > 1)
                dinic.addEdge(ID[i][j], ID[i][j - 1], INF);

            if (j < M)
                dinic.addEdge(ID[i][j], ID[i][j + 1], INF);
        }
    }

    dinic.init();

    std::cout << (sum - dinic.maxFlow(S, T)) << std::endl;

    return 0;
}

骑士共存问题

方格取数问题 / 王者之剑,我们可以发现可以相互攻击到的格子肯定是一个奇数和一个偶数。

那么可以使用与上述题目相同的方法去处理可以相互攻击到的格子。

对于限制不能使用的格子,若其横纵坐标之和为奇数,那么可以从其连一条向汇点,容量为 \(\infty\) 的边,因此源点连向这个点的边一定会被割掉,进而确保其一定不会被选择。对于横纵坐标之和为偶数的节点同理。

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

typedef long long valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;

class Dinic {
private:
    struct Edge {
    public:
        typedef std::list<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){};
    };

    typedef std::vector<Edge::container> Graph;
    typedef std::vector<Edge::iterator> IterVector;

    valueType N;
    Graph G;
    ValueVector depth;
    IterVector start;
    bool Initialized;

public:
    explicit Dinic(valueType N) : N(N), G(N + 1), depth(N + 1, 0), start(N + 1), Initialized(false){};

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

        G[from].emplace_back(to, cap);
        G[to].emplace_back(from, 0);
        G[from].back().pair = std::prev(G[to].end());
        G[to].back().pair = std::prev(G[from].end());
    }

    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])
                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);
        }

        return result;
    }

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 &e : G[u]) {
                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 &e = Begin[u]; e != G[u].end(); ++e) {
            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;
    }
};

constexpr valueType INF = std::numeric_limits<valueType>::max();

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

    valueType N, M;

    std::cin >> N >> M;

    valueType size = 0;

    valueType const S = ++size, T = ++size;

    ValueMatrix ID(N + 1, ValueVector(N + 1, 0));

    for (valueType i = 1; i <= N; ++i)
        for (valueType j = 1; j <= N; ++j)
            ID[i][j] = ++size;

    Dinic dinic(size);

    valueType sum = N * N;

    for (valueType i = 1; i <= N; ++i) {
        for (valueType j = 1; j <= N; ++j) {
            if (((i + j) & 1) == 1) {
                dinic.addEdge(S, ID[i][j], 1);
            } else {
                dinic.addEdge(ID[i][j], T, 1);
            }
        }
    }

    for (valueType i = 1; i <= N; ++i) {
        for (valueType j = 1; j <= N; ++j) {
            if (((i + j) & 1) == 0)
                continue;

            if (i - 2 >= 1 && j - 1 >= 1)
                dinic.addEdge(ID[i][j], ID[i - 2][j - 1], INF);

            if (i + 2 <= N && j - 1 >= 1)
                dinic.addEdge(ID[i][j], ID[i + 2][j - 1], INF);

            if (i - 2 >= 1 && j + 1 <= N)
                dinic.addEdge(ID[i][j], ID[i - 2][j + 1], INF);

            if (i + 2 <= N && j + 1 <= N)
                dinic.addEdge(ID[i][j], ID[i + 2][j + 1], INF);

            if (i - 1 >= 1 && j - 2 >= 1)
                dinic.addEdge(ID[i][j], ID[i - 1][j - 2], INF);

            if (i + 1 <= N && j - 2 >= 1)
                dinic.addEdge(ID[i][j], ID[i + 1][j - 2], INF);

            if (i - 1 >= 1 && j + 2 <= N)
                dinic.addEdge(ID[i][j], ID[i - 1][j + 2], INF);

            if (i + 1 <= N && j + 2 <= N)
                dinic.addEdge(ID[i][j], ID[i + 1][j + 2], INF);
        }
    }

    for (valueType i = 0; i < M; ++i) {
        valueType x, y;

        std::cin >> x >> y;

        if (((x + y) & 1) == 1) {
            dinic.addEdge(ID[x][y], T, INF);
        } else {
            dinic.addEdge(S, ID[x][y], INF);
        }
    }

    dinic.init();

    std::cout << (sum - dinic.maxFlow(S, T)) << std::endl;

    return 0;
}

CF1473F Strange Set

我们可以发现有若干形如

\(\mathbf{A}\) 入选,那么 \(\mathbf{B}\) 一定入选

的限制。

考虑最小割,设 \(S\) 集合代表选择的下标,\(T\) 集合代表不被选择的下标。

那么对于所有的限制条件 \(\left(A, B\right)\),可以连边 \(A \rightarrow B\),容量为 \(\infty\)

但是由于本题空间限制很小,如此连边会导致 \(\tt{MLE}\)

发现值域很小,故我们可以考虑向每种值在当前节点之前、最后一次出现的节点连边,而被连边的节点又一定会和其他在更前方且符合要求的节点连边,因此可以保证正确性。

由于 \(100\) 以内的因子最多的数的因子个数为 \(12\) 个。所以边数是 \(\mathcal{O}(n)\) 级别的。

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

typedef long long valueType;
typedef std::vector<valueType> ValueVector;

class Dinic {
private:
    struct Edge {
    public:
        typedef std::list<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){};
    };

    typedef std::vector<Edge::container> Graph;
    typedef std::vector<Edge::iterator> IterVector;

    valueType N;
    Graph G;
    ValueVector depth;
    IterVector start;
    bool Initialized;

public:
    explicit Dinic(valueType N) : N(N), G(N + 1), depth(N + 1, 0), start(N + 1), Initialized(false){};

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

        G[from].emplace_back(to, cap);
        G[to].emplace_back(from, 0);
        G[from].back().pair = std::prev(G[to].end());
        G[to].back().pair = std::prev(G[from].end());
    }

    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])
                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);
        }

        return result;
    }

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 &e : G[u]) {
                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 &e = Begin[u]; e != G[u].end(); ++e) {
            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;
    }
};

constexpr valueType INF = std::numeric_limits<valueType>::max();

constexpr valueType V = 100;

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

    valueType N;

    std::cin >> N;

    ValueVector A(N + 1, 0), B(N + 1, 0), ID(N + 1, 0), last(V + 1, 0);

    valueType size = 0;

    valueType const S = ++size, T = ++size;

    for (valueType i = 1; i <= N; ++i)
        ID[i] = ++size;

    Dinic dinic(size);

    for (valueType i = 1; i <= N; ++i)
        std::cin >> A[i];

    for (valueType i = 1; i <= N; ++i)
        std::cin >> B[i];

    ValueVector father(N + 1, INF);

    for (valueType i = 1; i <= N; ++i) {
        for (valueType j = 1; j <= V; ++j)
            if (A[i] % j == 0 && last[j] != 0)
                dinic.addEdge(ID[i], ID[last[j]], INF);

        last[A[i]] = i;
    }

    valueType sum = 0;

    for (valueType i = 1; i <= N; ++i) {
        if (B[i] > 0) {
            sum += B[i];

            dinic.addEdge(S, ID[i], B[i]);
        } else if (B[i] < 0) {
            dinic.addEdge(ID[i], T, -B[i]);
        }
    }

    dinic.init();

    std::cout << (sum - dinic.maxFlow(S, T)) << std::endl;

    return 0;
}

CF1061E Politics

对于每个节点,我们可以找到其祖先中深度最高且被限制的节点。这样我们就可以把一棵树划分为若干节点集合,同时有对于每个集合需要选择指定数量的节点的限制。

考虑如何处理这两组限制,考虑建出网络,若网络的流量可以流满那么就代表着存在方案。

对于第一棵树的每个限制 \(\left(x_i, k_i\right)\),设其代表 \(x_i\) 所代表的集合要恰好存在 \(k_i\) 个节点被选择,那么我们可以建一条边 \(S \rightarrow x_{i, 1}\),容量为 \(k_i\)。对于第二棵树的每个限制 \(\left(x_i, k_i\right)\),我们可以建一条边 \(x_{i, 2} \rightarrow T\),容量为 \(k_i\)

接下来处理节点的对应关系,对于每个节点 \(i\),我们设其在第一棵树上属于点 \(l_i\),在第二棵树上属于点 \(r_i\),那么我们可以建边 \(l_i \rightarrow r_i\),容量为 \(1\)

接下来考虑如何最大化收益,我们可以使用最大费用最大流,对于节点所属集合之间的连边加上其对应的收益即可。

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

typedef long long valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;

template<typename T = valueType, typename Compare = std::less<T>>
class MCMF {
private:
    struct Edge {
    public:
        typedef std::list<Edge> container;
        typedef typename container::iterator iterator;

        T to;
        T cap;
        T flow;
        T cost;
        iterator pair;

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

        Edge(T to, T cap, T c, iterator pair = iterator()) : to(to), cap(cap), flow(0), cost(c),
                                                             pair(pair){};
    };

    typedef std::vector<typename Edge::container> Graph;
    typedef std::vector<typename Edge::iterator> IterVector;
    typedef std::vector<bool> bitset;

    T N;
    Graph G;
    std::vector<T> dist;
    IterVector start;
    bool Initialized;

public:
    explicit MCMF(T N) : N(N), G(N + 1), dist(N + 1, 0), start(N + 1), Initialized(false){};

    typename Edge::iterator addEdge(T from, T to, T cap, T cost) {
        if (__builtin_expect(Initialized, false))
            throw std::runtime_error("MCMF: addEdge after init");

        G[from].emplace_back(to, cap, cost);
        G[to].emplace_back(from, 0, -cost);
        G[from].back().pair = std::prev(G[to].end());
        G[to].back().pair = std::prev(G[from].end());

        return std::prev(G[from].end());
    }

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

        Initialized = true;

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

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

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

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

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

        Initialized = false;
    }

    std::pair<T, T> maxFlow(T _S, T _T) {
        if (__builtin_expect(!Initialized, false))
            throw std::runtime_error("MCMF: maxFlow before init");

        std::pair<T, T> result(0, 0);

        while (bfs(_S, _T)) {
            IterVector begin = start;

            bitset visited(N + 1, false);

            T const flow = dfs(_S, _T, std::numeric_limits<T>::max(), begin, visited);

            result.first += flow;
            result.second += flow * dist[_T];
        }

        return result;
    }

private:
    bool bfs(T _S, T _T) {
        static_assert(std::is_same<Compare, std::less<T>>::value || std::is_same<Compare, std::greater<T>>::value || std::is_same<Compare, std::less<>>::value || std::is_same<Compare, std::greater<>>::value, "MCMF: bfs only support less or greater");

        static valueType const constexpr initValue = std::is_same<Compare, std::less<T>>::value || std::is_same<Compare, std::less<>>::value ? std::numeric_limits<T>::max() : std::numeric_limits<T>::min();

        std::fill(dist.begin(), dist.end(), initValue);

        bitset visited(N + 1, false);

        std::queue<T> Q;

        Q.push(_S);
        dist[_S] = 0;
        visited[_S] = true;

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

            visited[u] = false;
            Q.pop();

            for (auto const &e : G[u]) {
                if (e.cap > e.flow && Compare()(dist[u] + e.cost, dist[e.to])) {
                    dist[e.to] = dist[u] + e.cost;

                    if (!visited[e.to]) {
                        Q.push(e.to);
                        visited[e.to] = true;
                    }
                }
            }
        }

        return dist[_T] != initValue;
    }

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

        T result = 0;

        visited[u] = true;

        for (auto &e = Begin[u]; e != G[u].end() && flow > 0; ++e) {
            if (!visited[e->to] && e->cap > e->flow && dist[e->to] == dist[u] + e->cost) {
                T const f = dfs(e->to, _T, std::min(flow - result, e->cap - e->flow), Begin, visited);

                if (f == 0) {
                    dist[e->to] = std::numeric_limits<T>::max();

                    continue;
                }

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

                result += f;

                if (result == flow) {
                    visited[u] = false;

                    return flow;
                }
            }
        }

        visited[u] = false;

        return result;
    }
};

void fail() {
    std::cout << -1 << std::endl;

    std::exit(0);
}

class Tree {
private:
    valueType N, ROOT;
    ValueVector limit, sum, belong;
    ValueMatrix G;

public:
    Tree(valueType N = 0) : N(N), ROOT(1), limit(N + 1, -1), sum(N + 1, 0), belong(N + 1, 0), G(N + 1){};

    void addEdge(valueType u, valueType v) {
        G[u].emplace_back(v);
        G[v].emplace_back(u);
    }

    void setLimit(valueType x, valueType k) {
        limit[x] = k;
    }

    void setRoot(valueType x) {
        ROOT = x;
    }

    void solve() {
        dfs(ROOT, 0);
        push(ROOT, 0, ROOT);
    }

    valueType getBelong(valueType x) const {
        return belong[x];
    }

    valueType getSum() const {
        return sum[ROOT];
    }

    valueType getSum(valueType x) const {
        return sum[x];
    }

    valueType getLimit(valueType x) const {
        return limit[x];
    }

private:
    void dfs(valueType x, valueType from) {
        valueType const pre = limit[x];

        for (auto const &iter : G[x]) {
            if (iter == from)
                continue;

            dfs(iter, x);

            sum[x] += sum[iter];
        }

        if (limit[x] > 0) {
            valueType const next = limit[x] - sum[x];
            sum[x] = limit[x];
            limit[x] = next;

            if (next < 0)
                fail();
        }
    }

    void push(valueType x, valueType from, valueType tag) {
        if (limit[x] >= 0)
            tag = x;

        belong[x] = tag;

        for (auto const &iter : G[x]) {
            if (iter == from)
                continue;

            push(iter, x, tag);
        }
    }
};

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

    valueType N;

    std::cin >> N;

    Tree left(N), right(N);

    {
        valueType ROOT;

        std::cin >> ROOT;

        left.setRoot(ROOT);
    }

    {
        valueType ROOT;

        std::cin >> ROOT;

        right.setRoot(ROOT);
    }

    ValueVector A(N + 1, 0);

    for (valueType i = 1; i <= N; ++i)
        std::cin >> A[i];

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

        std::cin >> u >> v;

        left.addEdge(u, v);
    }

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

        std::cin >> u >> v;

        right.addEdge(u, v);
    }

    {
        valueType Q;

        std::cin >> Q;

        for (valueType i = 0; i < Q; ++i) {
            valueType x, k;

            std::cin >> x >> k;

            left.setLimit(x, k);
        }
    }

    {
        valueType Q;

        std::cin >> Q;

        for (valueType i = 0; i < Q; ++i) {
            valueType x, k;

            std::cin >> x >> k;

            right.setLimit(x, k);
        }
    }

    left.solve();
    right.solve();

    valueType size = 0;

    valueType const S = ++size, T = ++size;

    ValueVector leftID(N + 1, 0), rightID(N + 1, 0);

    for (valueType i = 1; i <= N; ++i)
        if (left.getBelong(i) == i)
            leftID[i] = ++size;

    for (valueType i = 1; i <= N; ++i)
        if (right.getBelong(i) == i)
            rightID[i] = ++size;

    MCMF<valueType, std::greater<>> mcmf(size);

    for (valueType i = 1; i <= N; ++i) {
        if (left.getBelong(i) == i)
            mcmf.addEdge(S, leftID[i], left.getLimit(i), 0);

        if (right.getBelong(i) == i)
            mcmf.addEdge(rightID[i], T, right.getLimit(i), 0);
    }

    if (left.getSum() != right.getSum())
        fail();

    for (valueType i = 1; i <= N; ++i)
        if (left.getBelong(i) > 0 && right.getBelong(i) > 0)
            mcmf.addEdge(leftID[left.getBelong(i)], rightID[right.getBelong(i)], 1, A[i]);

    mcmf.init();

    auto const result = mcmf.maxFlow(S, T);

    valueType ans = result.second;

    if (right.getSum() != result.first)
        fail();

    std::cout << ans << std::endl;

    return 0;
}
posted @ 2023-12-07 21:54  User-Unauthorized  阅读(14)  评论(0编辑  收藏  举报