Submission #434983

#TimeUsernameProblemLanguageResultExecution timeMemory
434983model_codeKeys (IOI21_keys)C++17
67 / 100
3055 ms80168 KiB
/** * Task: keys * Author: Kian Mirjalali * Solution: m*log(n) */ #include "keys.h" #include <iostream> #include <memory> #include <algorithm> #include <map> #include <set> using namespace std; #define tpc(C) template<class C> #define allOf(c) ((c).begin()), ((c).end()) #define fori(i, a, b) for (int i = (a); i < int(b); i++) #define forn(i, n) fori(i, 0, (n)) #define dbg(x) #x << "=" << x #define show(x) cerr << dbg(x) << endl typedef vector<int> VI; typedef vector<bool> VB; typedef pair<int, int> PII; tpc(C) inline int sz(const C& c) { return c.size(); } ///////////////////////// struct DisjointSet { VI par; inline DisjointSet(int n): par(n) { forn(i, n) par[i] = i; } inline int findRoot(int x) { int i; for (i = x; par[i] != i; ) i = par[i]; int root = i; for (i = x; par[i] != i; ) { int j = par[i]; par[i] = root; i = j; } return root; } /// returns true if the merge happened now or false if they are already merged inline bool merge(int x, int y) { int x_root = findRoot(x); int y_root = findRoot(y); if (x_root == y_root) return false; par[x_root] = y_root; return true; } }; ///////////////////////// class IndexDSBase { protected: int index_limit_; VI index_list; VI index_position; int list_head; inline void check_index_validity(int index) const { if (index < 0 || index_limit_ <= index) { cerr << "invalid index " << index << endl; exit(10); } } /// returns true if the index is added now or false if the index already existed inline bool add(int index) { //validity of index is checked in contains() if (contains(index)) return false; index_position[index] = list_head; index_list[list_head++] = index; return true; } public: inline IndexDSBase(int index_limit): index_limit_(index_limit), index_list(index_limit), index_position(index_limit), list_head(0) { } inline void clear() { list_head = 0; } inline bool contains(int index) const { check_index_validity(index); int pos = index_position[index]; return 0 <= pos && pos < list_head && index_list[pos] == index; } }; /// Performs operations in O(1) time struct IndexSet: public IndexDSBase { using IndexDSBase::IndexDSBase; using IndexDSBase::add; }; /// Performs operations in O(1) time tpc(T) class IndexMap: public IndexDSBase { vector<T> index_value; public: inline IndexMap(int index_limit): IndexDSBase(index_limit), index_value(index_limit) { } inline T& operator[](int index) { //validity of index is checked in add() if (add(index)) index_value[index] = T(); return index_value[index]; } }; ///////////////////////// int n, m, k; VI vertex_key; vector<vector<PII>> adj; unique_ptr<DisjointSet> djs; ///////////////////////// int span_head; int valid_root; VI span; unique_ptr<IndexSet> mark; unique_ptr<IndexSet> key_available; unique_ptr<IndexMap<VI>> key_locked_adj; inline void add2span(int x) { if (djs->findRoot(x) != valid_root) throw x; mark->add(x); span[span_head++] = x; } inline int compute_span(int root) { key_available->clear(); span_head = 0; key_locked_adj->clear(); mark->clear(); valid_root = djs->findRoot(root); add2span(root); for (int tail = 0; tail<span_head; tail++) { //show(tail); int x = span[tail]; int x_key = vertex_key[x]; if (key_available->add(x_key)) { for (int y : (*key_locked_adj)[x_key]) if (!mark->contains(y)) add2span(y); (*key_locked_adj)[x_key].clear(); } for (auto p: adj[x]) if (!mark->contains(p.first)) { if (key_available->contains(p.second)) add2span(p.first); else (*key_locked_adj)[p.second].push_back(p.first); } } return span_head; } VI find_reachable(VI r, VI u, VI v, VI c) { n = sz(r); m = sz(c); k = max(*max_element(allOf(r)), *max_element(allOf(c)))+1; vertex_key = r; adj.assign(n, vector<PII>()); forn(j, m) { adj[u[j]].emplace_back(v[j], c[j]); adj[v[j]].emplace_back(u[j], c[j]); } djs = make_unique<DisjointSet>(n); mark = make_unique<IndexSet>(n); key_available = make_unique<IndexSet>(k); key_locked_adj = make_unique<IndexMap<VI>>(k); span.resize(n); map<int, VI> finalized_span; VI active_roots(n); forn(i, n) active_roots[i] = i; int min_span = n+1; while (!active_roots.empty()) { //show(active_roots.size()); vector<PII> to_merge; VB is_active(n, false); for (int a : active_roots) { //show(a); try { int ss = compute_span(a); //show(ss); min_span = min(min_span, ss); finalized_span[a] = VI(span.begin(), span.begin()+span_head); } catch (int b) { //show(b); to_merge.emplace_back(a, b); is_active[a] = true; } } for (auto p : to_merge) if (djs->merge(p.first, p.second)) is_active[p.first] = false; active_roots.clear(); forn(i, n) if (is_active[i]) active_roots.push_back(i); } key_locked_adj.reset(nullptr); key_available.reset(nullptr); mark.reset(nullptr); djs.reset(nullptr); VI ans(n, 0); for (auto p : finalized_span) if (sz(p.second) == min_span) for (int x : p.second) ans[x] = 1; return ans; }
#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...