제출 #475862

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

bool DBG = 1;

void asrt(bool b)
{
    if(!b)
    {
        cerr << "failed!\n";
        while(1);
    }
}

struct disjoint_set
{
    int N;

    vector<int> parent;
    vector<int> parent_edge; //xor

    vector<int> subtree;

    stack<int> ops;
    stack<bool> bipartite;

    stack< stack<int> > compress_node;
    stack< stack<int> > prev_parent;
    stack< stack<int> > prev_toggle;

    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 = 0; i <= N; i++)
        {
            parent[i] = i;
            parent_edge[i] = 0;
            subtree[i] = 1;
        }

        ops.push(0);
        bipartite.push(1);
    }

    void compress(int u)
    {
        bool toggle = 0;
        int v = u;
        for(v = u; parent[v] != v; v = parent[v])
        {
            toggle ^= parent_edge[v];
        }

        if(v == parent[u] || v == u)
        {
            compress_node.top().push(-1);
            prev_parent.top().push(-1);
            prev_toggle.top().push(-1);
        }
        else
        {
            compress_node.top().push(u);
            prev_parent.top().push(parent[u]);
            prev_toggle.top().push(parent_edge[u]);

            parent[u] = v;
            parent_edge[u] = toggle;
        }
    }

    void decompress()
    {
        int u = compress_node.top().top();
        int v = prev_parent.top().top();
        int t = prev_toggle.top().top();

        asrt(!compress_node.empty());
        asrt(!prev_parent.empty());
        asrt(!prev_toggle.empty());

        asrt(!compress_node.top().empty());
        asrt(!prev_parent.top().empty());
        asrt(!prev_toggle.top().empty());

        compress_node.top().pop();
        prev_parent.top().pop();
        prev_toggle.top().pop();

        if(t != -1)
        {
            parent[u] = v;
            parent_edge[u] = t;
        }
    }

    int root(int u)
    {
        while(parent[u] != u)
            u = parent[u];
        return u;
    }

    void join(int u, int v)
    {
        // cerr << "join " << u << ' ' << v << '\n';
        int opp = 1;
        compress_node.push(stack<int>{});
        prev_parent.push(stack<int>{});
        prev_toggle.push(stack<int>{});

        compress(u);
        compress(v);

        while(u != parent[u])
        {
            opp ^= parent_edge[u];
            u = parent[u];
        }

        while(v != parent[v])
        {
            opp ^= parent_edge[v];
            v = parent[v];
        }

        if(u == v)
        {
            ops.push(0);
            if(bipartite.top())
            {
                if(opp == 0) bipartite.push(1);
                else bipartite.push(0);
            }
            else bipartite.push(0);
        }
        else
        {
            if(subtree[u] < subtree[v]) swap(u, v);
            parent[v] = u;
            parent_edge[v] = opp;

            subtree[u] += subtree[v];

            ops.push(v);
            bipartite.push( bipartite.top() );
        }
    }

    void rollback()
    {
        // cerr << "rollback\n";
        int u = ops.top();

        ops.pop();
        bipartite.pop();

        subtree[ parent[u] ] -= subtree[u];
        parent[u] = u;
        parent_edge[u] = 0;

        while(!(compress_node.top()).empty())
        {
            decompress();
        }
        asrt(!compress_node.empty());
        asrt(!prev_parent.empty());
        asrt(!prev_toggle.empty());
        compress_node.pop();
        prev_parent.pop();
        prev_toggle.pop();
    }

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

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(DBG) while(1);
        // 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)
    {
        if(DBG) while(1);
        contract_left();
    }

    // if(F)cerr<<"lmid="<<lmid<<"\n";

    if(!DSU.is_bipartite())
    {
        if(DBG) while(1);
        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)
    {
        if(DBG) while(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)
    {
        if(DBG) while(1);
        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()
{
if(N+M+Q > 15)
    while(1);
    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:235:10: warning: variable 'F' set but not used [-Wunused-but-set-variable]
  235 |     bool F = 0;
      |          ^
Joker.cpp: In function 'int main()':
Joker.cpp:366:1: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
  366 | if(N+M+Q > 15)
      | ^~
Joker.cpp:368:5: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
  368 |     ios_base::sync_with_stdio(false);
      |     ^~~~~~~~
#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...