제출 #477115

#제출 시각아이디문제언어결과실행 시간메모리
477115blueJoker (BOI20_joker)C++17
100 / 100
566 ms22848 KiB
#include <iostream>
#include <vector>
#include <stack>
#include <cassert>
using namespace std;
 
void asrt(bool b)
{
    if(!b)
    {
        cerr << "failed!\n";
        while(1);
    }
}
 
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;
        }
    }

    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);

        op_node.push_back(u);
        op_oldparent.push_back(parent[u]);
        op_oldxor.push_back(parent_edge[u]);
        op_time.push_back(curr_time);
        bipartite.push_back(bipartite.back());
        subtree_change.push_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';

            op_node.push_back(V.first);
            op_oldparent.push_back(parent[V.first]);
            op_oldxor.push_back(parent_edge[V.first]);
            op_time.push_back(curr_time);
            bipartite.push_back(bipartite.back());
            subtree_change.push_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();

            op_node.pop_back();
            op_oldparent.pop_back();
            op_oldxor.pop_back();
            op_time.pop_back();
            bipartite.pop_back();
            subtree_change.pop_back();

            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]);
}
 
bool flag = 0;
 
void solve(int l1, int l2, int r1, int r2) // [L, R] == [l1, r2] at the beginning
{
    // cerr << "solve " << l1 << ' ' << l2 << ' ' << r1 << ' ' << r2 << '\n';
    bool F = 0;
    if(l1 <= 8 && 8 <= l2) F = 1;
    // assert(L == l1);
    // assert(R == r2);
    int lmid = (l1+l2)/2;
    int rmid;
 
    flag = 0;
    // dbg(lmid);
    // cerr << "hello\n";
 
    // if(F) cerr << "special solve " << l1 << ' ' << l2 << ' ' << r1 << ' ' << r2 << '\n';
 
    if(!DSU.is_bipartite())
    {
        // if(F) cerr << "!!!!\n";
        // if(!F)
        // {
        //     cerr << L << ' ' << R << '\n';
        //     cerr << "???????\n";
        //
        //
        //         cerr << "###\n";
        //
        //
        //     cerr << "DSU: ";
        //     for(int i = 1; i <= N; i++) cerr << DSU.root(i) << ' ';
        //     cerr << '\n';
        // }
        // cerr << "check\n";
        // cerr << l1 << ' ' << l2 << " emergency\n";
        // cerr << lmid << '\n';
        // cerr << "M = " << M << '\n';
        for(int i = lmid; i <= l2; i++)
        {
            minR[i] = M+1;
            // cerr << minR[i] << '\n';
        }
        if(l1 <= lmid-1)
        {
            solve(l1, lmid-1, r1, r2); //ADJUST L AND R!!!!! -> not necessary
        }
        return;
    }
 
    // cerr <<
    // for(int i = 1; i <= N; i++) dbg(to_string(i), DSU.root(i));
    // dbg(DSU.is_bipartite());
 
    while(L < lmid)
        contract_left();
 
    // if(F)cerr<<"lmid="<<lmid<<"\n";
 
    if(!DSU.is_bipartite())
    {
        while(l1 < L)
            expand_left();
        // cerr << "check\n";
        // cerr << l1 << ' ' << l2 << " emergency\n";
        // cerr << lmid << '\n';
        // cerr << "M = " << M << '\n';
        for(int i = lmid; i <= l2; i++)
        {
            minR[i] = M+1;
            // cerr << minR[i] << '\n';
        }
        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())
    {
        // cerr << "bipartite = yes\n";
        rmid = min(rmid, R);
        contract_right();
    }
    // cerr << "rmid = " << rmid << '\n';
 
    minR[lmid] = rmid;
 
    while(R < r2)
        expand_right();
    while(l1 < L)
        expand_left();
 
    // assert(L == l1 && R == r2);
 
    if(l1 <= lmid-1)
    {
        while(rmid < R)
            contract_right();
 
        // assert(L == l1 && R == rmid);
        solve(l1, lmid-1, r1, rmid);
 
        while(R < r2)
            expand_right();
    }
 
    if(lmid+1 <= l2)
    {
        while(L < lmid+1)
            contract_left();
 
        // assert(L == lmid+1 && R == r2);
        solve(lmid+1, l2, rmid, r2);
 
        while(l1 < L)
            expand_left();
    }
 
    // assert(L == l1 && R == r2);
}
 
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 j = 1; j <= M; j++) cerr << minR[j] << ' ';
    // cerr << '\n';
 
    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
    }
}

컴파일 시 표준 에러 (stderr) 메시지

Joker.cpp: In function 'void solve(int, int, int, int)':
Joker.cpp:196:10: warning: variable 'F' set but not used [-Wunused-but-set-variable]
  196 |     bool F = 0;
      |          ^
#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...