Submission #477117

#TimeUsernameProblemLanguageResultExecution timeMemory
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...