QOJ.ac

QOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#562904#9102. Zayin and Elementsucup-team004AC ✓1ms3704kbC++205.8kb2024-09-13 22:42:362024-09-13 22:42:37

Judging History

你现在查看的是最新测评结果

  • [2024-09-13 22:42:37]
  • 评测
  • 测评结果:AC
  • 用时:1ms
  • 内存:3704kb
  • [2024-09-13 22:42:36]
  • 提交

answer

#include <bits/stdc++.h>

using i64 = long long;
using u64 = unsigned long long;
using u32 = unsigned;

constexpr int inf = 1E9;
struct Graph {
    int n;
    std::vector<std::vector<int>> e;
    Graph(int n) : n(n), e(n) {}
    void addEdge(int u, int v) {
        e[u].push_back(v);
        e[v].push_back(u);
    }
    std::vector<int> findMatching(int m, const auto &init) {
        std::vector<int> match(n, -1), vis(n), link(n), f(n), dep(n);
        for (auto [x, y] : init) {
            match[x] = y;
            match[y] = x;
        }
        // disjoint set union
        auto find = [&](int u) {
            while (f[u] != u)
                u = f[u] = f[f[u]];
            return u;
        };
        auto lca = [&](int u, int v) {
            u = find(u);
            v = find(v);
            while (u != v) {
                if (dep[u] < dep[v])
                    std::swap(u, v);
                u = find(link[match[u]]);
            }
            return u;
        };
        std::queue<int> que;
        auto blossom = [&](int u, int v, int p) {
            while (find(u) != p) {
                link[u] = v;
                v = match[u];
                if (vis[v] == 0) {
                    vis[v] = 1;
                    que.push(v);
                }
                f[u] = f[v] = p;
                u = link[v];
            }
        };
        // find an augmenting path starting from u and augment (if exist)
        auto augment = [&](int u) {
            while (!que.empty())
                que.pop();
            std::iota(f.begin(), f.end(), 0);
            // vis = 0 corresponds to inner vertices, vis = 1 corresponds to outer vertices
            std::fill(vis.begin(), vis.end(), -1);
            que.push(u);
            vis[u] = 1;
            dep[u] = 0;
            int y = -1;
            while (!que.empty()){
                int u = que.front();
                que.pop();
                if (u >= m) {
                    y = u;
                }
                for (auto v : e[u]) {
                    if (vis[v] == -1) {
                        vis[v] = 0;
                        link[v] = u;
                        dep[v] = dep[u] + 1;
                        // found an augmenting path
                        if (match[v] == -1) {
                            for (int x = v, y = u, temp; y != -1; x = temp, y = x == -1 ? -1 : link[x]) {
                                temp = match[y];
                                match[x] = y;
                                match[y] = x;
                            }
                            return;
                        }
                        vis[match[v]] = 1;
                        dep[match[v]] = dep[u] + 2;
                        que.push(match[v]);
                    } else if (vis[v] == 1 && find(v) != find(u)) {
                        // found a blossom
                        int p = lca(u, v);
                        blossom(u, v, p);
                        blossom(v, u, p);
                    }
                }
            }
            if (y != -1) {
                for (int x = -1, temp; y != -1; x = temp, y = x == -1 ? -1 : link[x]) {
                    temp = match[y];
                    if (x != -1) {
                        match[x] = y;
                    }
                    match[y] = x;
                }
            }
        };
        // find a maximal matching greedily (decrease constant)
        // auto greedy = [&]() {
        //     for (int u = 0; u < n; ++u) {
        //         if (match[u] != -1)
        //             continue;
        //         for (auto v : e[u]) {
        //             if (match[v] == -1) {
        //                 match[u] = v;
        //                 match[v] = u;
        //                 break;
        //             }
        //         }
        //     }
        // };
        // greedy();
        for (int u = 0; u < m; ++u)
            if (match[u] == -1)
                augment(u);
        return match;
    }
};
void solve() {
    int n, m;
    std::cin >> n >> m;
    
    int tot = n;
    std::vector<int> a(m), b(m), c(m);
    std::vector<std::vector<int>> adj(m);
    for (int i = 0; i < m; i++) {
        std::cin >> a[i] >> b[i] >> c[i];
        tot += a[i] + 2 * b[i] + 2 * c[i];
        int t;
        std::cin >> t;
        adj[i].resize(t);
        for (int j = 0; j < t; j++) {
            std::cin >> adj[i][j];
            adj[i][j]--;
        }
    }
    
    Graph g(tot);
    std::vector<std::array<int, 2>> init;
    int cur = n;
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < a[i]; j++) {
            for (auto v : adj[i]) {
                g.addEdge(v, cur);
            }
            cur++;
        }
        for (int j = 0; j < b[i]; j++) {
            for (auto v : adj[i]) {
                g.addEdge(v, cur);
                g.addEdge(v, cur + 1);
            }
            init.push_back({cur, cur + 1});
            g.addEdge(cur, cur + 1);
            cur += 2;
        }
        for (int j = 0; j < c[i]; j++) {
            for (auto v : adj[i]) {
                g.addEdge(v, cur);
            }
            init.push_back({cur, cur + 1});
            g.addEdge(cur, cur + 1);
            cur += 2;
        }
    }
    
    auto match = g.findMatching(n, init);
    if (std::find(match.begin(), match.begin() + n, -1) != match.begin() + n) {
        std::cout << -1 << "\n";
        return;
    }
    int ans = 0;
    for (int i = 0; i < tot; i++) {
        ans += (match[i] > i);
    }
    ans -= n;
    std::cout << ans << "\n";
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int t;
    std::cin >> t;
    
    while (t--) {
        solve();
    }
    
    return 0;
}

Details

Tip: Click on the bar to expand more detailed information

Test #1:

score: 100
Accepted
time: 0ms
memory: 3548kb

input:

2
5
2
2 3 1 2 3 1
1 1 1 3 4 5 2
5
2
2 3 1 1 3
1 0 1 2 1 2

output:

5
-1

result:

ok 2 lines

Test #2:

score: 0
Accepted
time: 1ms
memory: 3704kb

input:

5
9
10
0 0 10 2 3 8
0 0 10 2 4 6
0 8 2 2 2 4
0 0 10 3 1 3 8
0 4 6 2 2 3
0 8 2 3 2 6 7
0 9 1 2 1 7
0 2 8 3 1 4 9
0 7 3 1 5
0 0 10 3 5 6 9
3
10
0 9 1 1 2
0 5 5 1 1
0 1 9 1 1
0 7 3 1 1
0 7 3 0
0 0 10 0
0 6 4 1 3
0 9 1 0
0 7 3 0
0 9 1 1 2
90
20
0 6 4 12 1 4 5 22 32 64 66 67 73 87 88 89
0 1 9 12 3 8 21 3...

output:

94
97
155
151
152

result:

ok 5 lines