제출 #477117

#제출 시각아이디문제언어결과실행 시간메모리
477117blueJoker (BOI20_joker)C++17
100 / 100
563 ms19568 KiB
#include <iostream>
#include <vector>
#include <stack>
#include <cassert>
using namespace std;

struct disjoint_set
{
    int N;
    vector<int> parent;
    vector<int> parent_edge; //the color of this node is the xor of path up to parent
    vector<int> subtree;

    vector<int> op_node = vector<int>(1, 0);
    vector<int> op_oldparent = vector<int>(1, 0);
    vector<int> op_oldxor = vector<int>(1, 0);
    vector<int> op_time = vector<int>(1, 0);
    vector<bool> bipartite = vector<bool>(1, 1);
    vector<bool> subtree_change = vector<bool>(1, 0);

    int curr_time = 0;

    disjoint_set()
    {
        ;
    }

    disjoint_set(int N_)
    {
        N = N_;
        parent = vector<int>(1+N);
        parent_edge = vector<int>(1+N);
        subtree = vector<int>(1+N);
        for(int i = 1; i <= N; i++)
        {
            parent[i] = i;
            parent_edge[i] = 0;
            subtree[i] = 1;
        }
    }

    void add_entry(int u, int v, int x, bool b, bool s)
    {
        op_node.push_back(u);
        op_oldparent.push_back(v);
        op_oldxor.push_back(x);
        op_time.push_back(curr_time);
        bipartite.push_back(b);
        subtree_change.push_back(s);
    }

    void remove_entry()
    {
        op_node.pop_back();
        op_oldparent.pop_back();
        op_oldxor.pop_back();
        op_time.pop_back();
        bipartite.pop_back();
        subtree_change.pop_back();
    }

    pair<int, int> root(int u) //first = root, second = xor of root and u
    {
        int v = u;
        int edg = 0;
        while(parent[v] != v)
        {
            edg ^= parent_edge[v];
            v = parent[v];
        }

        if(v == u || v == parent[u]) return make_pair(parent[u], edg);


        add_entry(u, parent[u], parent_edge[u], bipartite.back(), 0);

        parent[u] = v;
        parent_edge[u] = edg;

        return make_pair(parent[u], parent_edge[u]);
    }

    void join(int u, int v)
    {
        curr_time++;

        pair<int, int> U = root(u);
        pair<int, int> V = root(v);

        if(U.first == V.first)
        {
            op_node.push_back(0);
            op_oldparent.push_back(0);
            op_oldxor.push_back(0);
            op_time.push_back(curr_time);

            if(U.second == V.second)
            {
                bipartite.push_back(0);
            }
            else
            {
                bipartite.push_back(bipartite.back());
            }

            subtree_change.push_back(0);
        }
        else
        {
            // cerr << "case 2\n";
            if(subtree[U.first] < subtree[V.first]) swap(U, V);
            // cerr << U.first << ' ' << V.first << '\n';

            add_entry(V.first, parent[V.first], parent_edge[V.first], bipartite.back(), 1);

            parent[V.first] = U.first;
            parent_edge[V.first] = 1 ^ V.second ^ U.second;
            subtree[U.first] += subtree[V.first];

            // cerr << U.first << ' ' << V.first << ' ' << parent[V.first] << '\n';
        }
    }

    void rollback()
    {
        while(op_time.back() == curr_time)
        {
            int u = op_node.back();
            int v = op_oldparent.back();
            int x = op_oldxor.back();
            bool s = subtree_change.back();

            remove_entry();

            if(s) subtree[ parent[u] ] -= subtree[u];
            parent[u] = v;
            parent_edge[u] = x;
        }

        curr_time--;
    }

    bool is_bipartite()
    {
        return bipartite.back();
    }
};

const int maxN = 200'000;
const int maxM = 200'000;

int N, M, Q;

vector<int> u(1+maxM), v(1+maxM);

vector<int> minR(1+maxN, 0);
//the minimum value of R so that if the roads i, ... R are blocked the graph is bipartite

disjoint_set DSU;

int L;
int R;

void expand_right()
{
    R++;
    DSU.rollback();
}

void contract_right()
{
    R--;
    DSU.join(u[R+1], v[R+1]);
}

void expand_left()
{
    L--;
    DSU.rollback();
}

void contract_left()
{
    L++;
    DSU.join(u[L-1], v[L-1]);
}

void solve(int l1, int l2, int r1, int r2) // [L, R] == [l1, r2] at the beginning
{
    int lmid = (l1+l2)/2;
    int rmid;

    if(!DSU.is_bipartite())
    {
        for(int i = lmid; i <= l2; i++)
        {
            minR[i] = M+1;
        }
        if(l1 <= lmid-1)
        {
            solve(l1, lmid-1, r1, r2); //ADJUST L AND R!!!!! -> not necessary
        }
        return;
    }

    while(L < lmid)
        contract_left();
    if(!DSU.is_bipartite())
    {
        while(l1 < L)
            expand_left();
        for(int i = lmid; i <= l2; i++)
        {
            minR[i] = M+1;
        }
        if(l1 <= lmid-1)
        {
            solve(l1, lmid-1, r1, r2); //ADJUST L AND R!!!!! -> not necessary
        }
        return;
    }
    // if(F) cerr << "check\n";

    rmid = r2;
    while(DSU.is_bipartite())
    {
        rmid = min(rmid, R);
        contract_right();
    }

    minR[lmid] = rmid;

    while(R < r2)
        expand_right();
    while(l1 < L)
        expand_left();
    if(l1 <= lmid-1)
    {
        while(rmid < R)
            contract_right();
            
        solve(l1, lmid-1, r1, rmid);

        while(R < r2)
            expand_right();
    }

    if(lmid+1 <= l2)
    {
        while(L < lmid+1)
            contract_left();
        solve(lmid+1, l2, rmid, r2);

        while(l1 < L)
            expand_left();
    }
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    cin >> N >> M >> Q;

    for(int j = 1; j <= M; j++) cin >> u[j] >> v[j];

    DSU = disjoint_set(N);

    disjoint_set temp(N);
    for(int j = 1; j <= M; j++) temp.join(u[j], v[j]);
    if(temp.is_bipartite())
    {
        int x;
        for(int u = 1; u <= Q; u++)
        {
            cin >> x >> x;
            cout << "NO\n";
        }
        return 0;
    }

    L = 1;
    R = M;
    solve(1, M, 1, M);

    for(int q = 1; q <= Q; q++)
    {
        int l, r;
        cin >> l >> r;

        if(minR[l] <= r) cout << "NO\n"; //bipartite
        else cout << "YES\n"; //not bipartite
    }
}
#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...