CF Round 818 F. Madoka and The First Session

在这里插入图片描述
简单思考一下,我们会发现对于 s ≠ 0 s \neq 0 s=0 的点,它们有几个 + 1 +1 +1和几个 − 1 -1 1都是固定了的。
我们不如只考虑 + 1 +1 +1,那么这就变成了一个二元组与点配对的问题。
很容易想到网络流。
我们将二元组作为左部点,分别向 U [ i ] U[i] U[i] V [ i ] V[i] V[i]连容量为 1 1 1的边。超级源点到每个左部点都连容量为 1 1 1的边,每个右部点向超级汇点连容量为其 + 1 +1 +1数量的边。
不过这样其实没能解决 s = 0 s=0 s=0的点的问题。对于这部分点,我们需要先将其向一个低级汇点连容量为 ∞ \infin 的边,接着从这个低级汇点向超级汇点连容量为 m − ∑ s [ u ] = 1 i n d e g [ u ] m-\sum_{s[u]=1}indeg[u] ms[u]=1indeg[u](这里的 i n d e g [ u ] indeg[u] indeg[u]是指,计算出的 u u u + 1 +1 +1数量)的边。
跑一个最大流,啪的一下,很快啊。

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 1e4 + 5;
const int inf = 0x3f3f3f3f;

struct networkflow {
    int tot;
    int ver[MAXN << 3], cap[MAXN << 3], nxt[MAXN << 3], head[MAXN << 1];
    networkflow() {
        tot = 1;
        memset(head, 0, sizeof(head));
    }
    void adde(int u, int v, int w) {
        ++tot;
        ver[tot] = v;
        cap[tot] = w;
        nxt[tot] = head[u];
        head[u] = tot;
    }
    void addedge(int u, int v, int w) {
        adde(u, v, w);
        adde(v, u, 0);
    }
    int d[MAXN << 1];
    bool bfs(int s, int t) {
        memset(d, 0, sizeof(d));
        queue<int> q;
        q.push(s);
        d[s] = 1;
        while (q.size()) {
            int u = q.front();
            q.pop();
            for (int i = head[u]; i; i = nxt[i]) {
                int v = ver[i];
                if (cap[i] && !d[v]) {
                    d[v] = d[u] + 1;
                    q.push(v);
                    if (v == t) return true;
                }
            }
        }
        return false;
    }
    int dinic(int u, int flow, const int &t) {
        if (u == t) return flow;
        int rest = flow, k;
        for (int i = head[u]; i; i = nxt[i]) {
            int v = ver[i];
            if (cap[i] && d[v] == d[u] + 1) {
                k = dinic(v, min(rest, cap[i]), t);
                if (!k) d[ver[i]] = 0;
                cap[i] -= k;
                cap[i ^ 1] += k;
                rest -= k;
                if (!rest) break;
            }
        }
        return flow - rest;
    }

    int maxflow(int s, int t) {
        int flow, res = 0;
        while (bfs(s, t))
            while (flow = dinic(s, inf, t))
                res += flow;
        return res;
    }
} NF;

int N, M;
int S[MAXN], A[MAXN], U[MAXN], V[MAXN], deg[MAXN], indeg[MAXN];

int main() {
    freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(false);
    cin >> N >> M;
    for (int i = 1; i <= N; i++)
        cin >> S[i];
    for (int i = 1; i <= N; i++)
        cin >> A[i];
    for (int i = 1; i <= M; i++) {
        cin >> U[i] >> V[i];
        ++deg[U[i]];
        ++deg[V[i]];
        NF.addedge(i + N, U[i], 1);
        NF.addedge(i + N, V[i], 1);
    }
    for (int i = 1; i <= M; i++)
        NF.addedge(N + M + 1, i + N, 1);
    int sum_of_indeg = 0;
    for (int i = 1; i <= N; i++) {
        if (!S[i]) continue;
        if ((deg[i] + A[i]) & 1) {
            cout << "NO" << endl;
            return 0;
        }
        indeg[i] = deg[i] + A[i] >> 1;
        sum_of_indeg += indeg[i];
    }
    if (sum_of_indeg > M || sum_of_indeg < 0) {
        cout << "NO" << endl;
        return 0;
    }
    for (int i = 1; i <= N; i++)
        if (S[i])
            NF.addedge(i, N + M + 3, indeg[i]);
        else
            NF.addedge(i, N + M + 2, inf);
    NF.addedge(N + M + 2, N + M + 3, M - sum_of_indeg);
    int maxflow = NF.maxflow(N + M + 1, N + M + 3);
    if (maxflow != M) {
        cout << "NO" << endl;
        return 0;
    } else {
        cout << "YES" << endl;
        for (int i = 1; i <= M; i++) {
            int idx1 = (i - 1) * 4 + 2, idx2 = (i - 1) * 4 + 4;
            int u = (!NF.cap[idx1] ? NF.ver[idx2] : NF.ver[idx1]);
            int v = U[i] ^ V[i] ^ u;
            cout << u << " " << v << endl;
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值