제출 #768136

#제출 시각아이디문제언어결과실행 시간메모리
768136adrilenJoker (BOI20_joker)C++17
100 / 100
1594 ms19228 KiB
#include<bits/stdc++.h>
#pragma GCC optimize("O3")
using namespace std;
using ll = long long;
typedef pair<int, int> pii;
typedef array<int, 2> arr;
typedef array<int, 3> arrr;

/*
Test group size

*/
constexpr int maxm = 2e5;
constexpr int sqrt_n = 800, sqrt_nn = maxm / sqrt_n + 1; 


struct UnionFind {
    vector <int> par; // >= 0 -> ind, < 0 -> siz
    vector <int> parity;
    vector <int> siz;

    vector <arr> history;

    UnionFind(int n, int m)
    {
        par.assign(n, -1);
        parity.assign(n, 0);
        siz.assign(n, 1);
    }

    pii fnd(int p)
    {
        if (par[p] < 0) return {p, 0};

        pii o = fnd(par[p]);
        o.second ^= parity[p];
        return o;
    }

    // Make a fnd with compression, such that it will be O(1)

    bool uni(int a, int b) // Return whether this will be an odd cycle
    {
        int a_parity, b_parity;
        tie(a, a_parity) = fnd(a);
        tie(b, b_parity) = fnd(b);

        if (a == b)
        {
            history.emplace_back(arr{-1, -1});
            if (a_parity == b_parity)
            {
                // Odd cycle
                return true;
            } else {
                return false;
            }
        }


        if (siz[a] < siz[b]) swap(a, b);
        // a > b
        // b will be merged into b

        siz[a] += siz[b];
        parity[b] = a_parity ^ b_parity ^ 1;
        par[b] = a;

        history.emplace_back(arr{a, b});
        return false;
    }

    void undo()
    {
        arr p = history.back();
        history.pop_back();
        if (p[0] == -1) return ;

        siz[p[0]] -= siz[p[1]];
        parity[p[1]] = 0;
        par[p[1]] = -1;
    }
} ;


int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    
    int n, m, q;
    cin >> n >> m >> q;

    vector<arr> edges(m);
    for (auto &i : edges) {
        cin >> i[0] >> i[1];
        i[0]--, i[1]--;
    }

    int b = 0;
    vector <arrr> queries(q);
    for (auto &i : queries)
    {
        cin >> i[0] >> i[1];
        i[0]--, i[1]--;
        i[2] = b++;
    }

    // Starting with the queries the furthest to the right
    sort(queries.begin(), queries.end(), [] (const auto &lhs, const auto &rhs)
    {
        return lhs[0] < rhs[0];
    });

    vector <int> min_start(sqrt_n, 2e9);
    vector <vector <arrr>> query_groups(sqrt_nn);
    for (auto &i : queries)
    {
        query_groups[i[0] / sqrt_n].emplace_back(i);
        min_start[i[0] / sqrt_n] = min(min_start[i[0] / sqrt_n], i[0]);
    }

    for (auto &i : query_groups) sort(i.begin(), i.end(), [] (const auto &lhs, const auto &rhs) {
        return lhs[1] > rhs[1];
    });
    

    vector <int> output(q);

    // Need to have a counter of whats already added


    int c = 0;
    for (auto &y : query_groups)
    {
        if (y.empty()) break;
        UnionFind Graph(n, m);


        auto already_added = edges.begin();
        bool have_found_cycle = false, this_cycle;

        while (already_added - edges.begin() < min_start[c]) {
            // Need to check if solved
            if (Graph.uni((*already_added)[0], (*already_added)[1])) {
                have_found_cycle = true;
            }
            already_added++;
        }


        auto right_edge = edges.end() - 1;
        auto left_edge = already_added;
        for (auto &i : y)
        {
            if (have_found_cycle) {
                output[i[2]] = true;
                continue;
            }

            // The right side

            // Check if the right amount
            while (right_edge - edges.begin() > i[1]) {
                if (Graph.uni((*right_edge)[0], (*right_edge)[1])) {
                    // All queries after this will be true
                    have_found_cycle = true;
                }
                right_edge--;
            }

            // The left side
            this_cycle = false;
            while (left_edge - edges.begin() < i[0])
            {
                if (Graph.uni((*left_edge)[0], (*left_edge)[1])) {
                    this_cycle = true;
                    left_edge++;
                    break;
                }
                left_edge++;
            }
            
            output[i[2]] = (this_cycle || have_found_cycle);

            // Remove last edges
            while (left_edge != already_added)
            {
                Graph.undo();
                left_edge--;
            }

        }
        c++;
    }

    for (auto &i : output) cout << (i ? "YES" : "NO") << "\n";
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...