Submission #1037450

#TimeUsernameProblemLanguageResultExecution timeMemory
1037450spacewalkerParachute rings (IOI12_rings)C++17
100 / 100
299 ms90124 KiB
#include <bits/stdc++.h> using namespace std; struct ComponentUnionFind { bool is_chains = true; vector<int> par; vector<int> _degree; int extra_edges = 0; ComponentUnionFind(int n) : par(n, -1), _degree(n, 0) {} int find(int i) { return par[i] < 0 ? i : (par[i] = find(par[i])); } int csize(int i) { return -par[find(i)]; } int degree(int i) { return _degree[i]; } bool join(int i, int j) { ++_degree[i]; ++_degree[j]; if (_degree[i] > 2 || _degree[j] > 2) is_chains = false; int ir = find(i), jr = find(j); if (ir == jr) { ++extra_edges; is_chains = false; return false; } if (par[ir] > par[jr]) { swap(i, j); swap(ir, jr); } par[ir] += par[jr]; par[jr] = ir; return true; } }; ComponentUnionFind create_from_ban(const vector<pair<int, int>> &edge_list, int n, int banned) { ComponentUnionFind cuf(n); for (auto [u, v] : edge_list) { if (u != banned && v != banned) cuf.join(u, v); } return cuf; } struct ParachuteRings { int n; vector<pair<ComponentUnionFind, int>> cufs; vector<pair<int, int>> edge_list; // size of the first cycle formed optional<int> critical_cycle_size; bool spoiled; ParachuteRings(int n) : n(n), cufs{{ComponentUnionFind(n), -1}}, spoiled(false) {} ParachuteRings() {} int count_critical() { if (spoiled) return 0; // here, we know the graph is NOT spoiled else if (cufs.size() > 1) { int ans = 0; for (auto &[cuf, _] : cufs) if (cuf.is_chains) ++ans; return ans; } else { // if we have no critical cycle, everything must still be chains return critical_cycle_size.value_or(n); } } void reset_cufs(int i) { vector<pair<ComponentUnionFind, int>> new_cufs; vector<int> bans; for (auto [u, v] : edge_list) { if (u == i) bans.push_back(v); if (v == i) bans.push_back(u); } bans.push_back(i); for (int v : bans) new_cufs.emplace_back(create_from_ban(edge_list, n, v), v); cufs = new_cufs; } void link(int i, int j) { edge_list.emplace_back(i, j); if (spoiled) return; if (cufs.size() > 1) { for (auto &[cuf, banned] : cufs) { if (!(i == banned || j == banned)) cuf.join(i, j); } } else { auto &cuf = cufs[0].first; bool cycle_created = !cuf.join(i, j); if (cuf.degree(i) > 2 || cuf.degree(j) > 2) { if (cuf.degree(i) > 2) reset_cufs(i); else reset_cufs(j); } else { // all nodes still have degree <= 2 // now, we must check for cycles // here, i guarantee cuf is still valid if (cycle_created) { if (cuf.extra_edges >= 2) { // we have two disjoint cycles, spoil the graph now spoiled = true; } else { critical_cycle_size = cuf.csize(i); } } } // if i fuck up here because i access cuf when i invalidated it that is // unironically a "muh memory safety!!!!!" moment } } void dump_state() { return; cerr << "!!! STATE DUMP " << endl; if (spoiled) cerr << "spoiled" << endl; else { cerr << "crit cycle " << critical_cycle_size.value_or(-1) << endl; cerr << cufs.size() << "simulations" << endl; for (auto &[cuf, banned] : cufs) { cerr << "cuf with ban" << banned << " = " << cuf.is_chains << endl; } } } }; ParachuteRings pr; void Init(int N) { pr = ParachuteRings(N); pr.dump_state(); } void Link(int A, int B) { pr.link(A, B); pr.dump_state(); } int CountCritical() { return pr.count_critical(); pr.dump_state(); }
#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...