Submission #768682

# Submission time Handle Problem Language Result Execution time Memory
768682 2023-06-28T11:43:53 Z jakobrs Joker (BOI20_joker) C++17
0 / 100
1 ms 340 KB
#pragma GCC optimize("O3")

#include <algorithm>
#include <iostream>
#include <vector>

using i64 = int64_t;
using i32 = int32_t;

struct Operation {
    i32 l1, r1;
};

constexpr i64 root(i64 n) {
    i64 i = 0;
    for (; i * i <= n; i++)
        ;
    return i - 1;
}

class UnionFind {
    std::vector<i32> parent;
    std::vector<i32> sizes;
    std::vector<bool> edge_parity;

    std::vector<Operation> operations;

   public:
    UnionFind(size_t sz)
        : parent(sz, -1), sizes(sz, 1), edge_parity(sz, false), operations() {}

    template <bool PATH_COMPRESSION>
    i32 find(i32 idx) {
        if (parent[idx] < 0)
            return idx;
        else if constexpr (PATH_COMPRESSION) {
            i64 root = find<PATH_COMPRESSION>(parent[idx]);
            edge_parity[idx] = edge_parity[idx] ^ edge_parity[parent[idx]];
            return parent[idx] = root;
        } else
            return find<PATH_COMPRESSION>(parent[idx]);
    }

    bool parity(i32 idx) {
        if (parent[idx] < 0)
            return false;
        else
            return parity(parent[idx]) ^ edge_parity[idx];
    }

    template <bool PATH_COMPRESSION>
    std::pair<i32, bool> both(i32 idx) {
        if constexpr (PATH_COMPRESSION) {
            return {find<true>(idx), parity(idx)};
        } else {
            // in this case there's an easy iterative version
            bool parity = false;

            while (parent[idx] >= 0) {
                parity = parity ^ edge_parity[idx];
                idx = parent[idx];
            }

            return {idx, parity};
        }
    }

    template <bool PATH_COMPRESSION>
    bool lag_fagforening(i32 l, i32 r) {
        auto [l1, lp] = both<PATH_COMPRESSION>(l);
        auto [r1, rp] = both<PATH_COMPRESSION>(r);

        operations.push_back({
            .l1 = l1,
            .r1 = r1,
        });

        if (l1 == r1) {
            return lp == rp;
        } else {
            if (sizes[l1] < sizes[r1]) {
                std::swap(l1, r1);
                std::swap(lp, rp);
            }

            sizes[l1] += sizes[r1];
            parent[r1] = l1;

            edge_parity[r1] = 1 ^ lp ^ rp;

            return false;
        }
    }

    void tvungen_lønnsnemnd() {
        auto [l1, r1] = operations.back();
        operations.pop_back();

        if (parent[r1] == l1) {
            parent[r1] = -1;
            sizes[l1] -= sizes[r1];
        } else if (parent[l1] == r1) {
            parent[l1] = -1;
            sizes[r1] -= sizes[l1];
        }

        edge_parity[l1] = edge_parity[r1] = false;
    }
};

struct {
    template <typename T>
    operator T() const {
        T x;
        std::cin >> x;
        return x;
    }
} in;

#define entire(v) std::begin(v), std::end(v)

#pragma GCC diagnostic ignored "-Wreturn-type"

main() {
    std::cin.tie(nullptr)->sync_with_stdio(false);

    i32 n, m, q;
    std::cin >> n >> m >> q;

    std::vector<std::pair<i32, i32>> edges(m);
    for (i32 i = 0; i < m; i++) {
        edges[i] = {(i32)in - 1, (i32)in - 1};
    }

    UnionFind dsu(n);

    static constexpr i32 root_m = 1024;

    struct Query {
        i32 l, r, i;
    };

    std::vector<Query> queries(q);
    for (i32 i = 0; i < q; i++) queries[i] = {(i32)in - 1, (i32)in, i};

    std::sort(entire(queries), [](auto &&lhs, auto &&rhs) {
        return std::pair<i32, i32>{lhs.l / root_m, -lhs.r} <
               std::pair<i32, i32>{rhs.l / root_m, -rhs.r};
    });

    std::vector<bool> answers(q);

    i32 l = 0;
    i32 r = 0;

    bool is_bipartite_left = true;
    for (i32 start = 0; start < m && is_bipartite_left; start += root_m) {
        l = r;
        while (r < q && queries[r].l < start + root_m) r++;

        bool is_bipartite_right = true;
        i32 w = m;
        for (; l < r && is_bipartite_right; l++) {
            for (w--; w >= queries[l].r && is_bipartite_right; w--)
                is_bipartite_right &= dsu.lag_fagforening<false>(edges[w].first, edges[w].second);

            if (!is_bipartite_right) break;

            bool is_bipartite = true;
            i32 g = start;
            for (; g < queries[l].l && is_bipartite; g++)
                is_bipartite &= dsu.lag_fagforening<false>(edges[g].first, edges[g].second);

            answers[queries[l].i] = is_bipartite;

            for (i32 u = start; u < g; u++) dsu.tvungen_lønnsnemnd();
        }

        if (!is_bipartite_right)
            for (; l < r; l++)
              answers[queries[l].i] = false;

        for (i32 x = w; x < m; x++) dsu.tvungen_lønnsnemnd();

        for (i32 y = start; y < start + root_m && y < m; y++)
            is_bipartite_left &= dsu.lag_fagforening<true>(edges[y].first, edges[y].second);
    }

    if (!is_bipartite_left)
        for (; l < q; l++)
            answers[queries[l].i] = false;

    for (auto x : answers) {
        std::cout << (x ? "NO\n" : "YES\n");
    }
}
# Verdict Execution time Memory Grader output
1 Runtime error 1 ms 340 KB Execution killed with signal 11
2 Halted 0 ms 0 KB -
# Verdict Execution time Memory Grader output
1 Runtime error 1 ms 340 KB Execution killed with signal 11
2 Halted 0 ms 0 KB -
# Verdict Execution time Memory Grader output
1 Runtime error 1 ms 340 KB Execution killed with signal 11
2 Halted 0 ms 0 KB -
# Verdict Execution time Memory Grader output
1 Runtime error 1 ms 340 KB Execution killed with signal 11
2 Halted 0 ms 0 KB -
# Verdict Execution time Memory Grader output
1 Runtime error 1 ms 340 KB Execution killed with signal 11
2 Halted 0 ms 0 KB -
# Verdict Execution time Memory Grader output
1 Runtime error 1 ms 340 KB Execution killed with signal 11
2 Halted 0 ms 0 KB -