Submission #926846

#TimeUsernameProblemLanguageResultExecution timeMemory
926846bobbilykingWerewolf (IOI18_werewolf)C++17
100 / 100
2064 ms135608 KiB
#include "werewolf.h" #include <bits/stdc++.h> using namespace std; using ll = int; #define F(i, l, r) for (ll i = (l); i < (r); ++i) #define A(a) (a).begin(), (a).end() using pl = pair<ll, ll>; using vl = vector<ll>; #define K first #define V second #define NN 200010 ll parent[NN]; vl dsuSet[NN]; ll find(ll i) { while ( i - parent[i]) i = parent[i]; return i; } optional<pair<pl, vl>> merge(ll i, ll j) { i = find(i), j = find(j); if (i-j) { if (dsuSet[i].size() < dsuSet[j].size()) swap(i, j); parent[j] = i; dsuSet[i].insert(dsuSet[i].end(), A(dsuSet[j])); return {pair(pair(i, j), dsuSet[j])}; } return {}; } // another alternate form of the kruskal reconstruction tree // We're trying to maintain, "does node E exists in my KRT subtree?" // Hard to maintain with normal KRT. // Instead, let's store in the event-KRT namespace krt { ll parent[NN]; map<ll, ll> nodesInSubtree[NN]; ll pw[NN]; ll find(ll i) { while (i - parent[i]) i = parent[i]; return i; } void merge(ll i, ll j, ll w) { i = find(i), j = find(j); if (i-j) { if (nodesInSubtree[i].size() < nodesInSubtree[j].size()) { swap(i, j); } for (auto &[x, _]: nodesInSubtree[j]) nodesInSubtree[i][x] = w; pw[j] = w; parent[j] = i; } } void init(ll n) { F(i, 0, n) { nodesInSubtree[i][i] = n-1; parent[i] = i; } } void change(ll node, ll relabelFrom, ll relabelTo) { // cout << "CHANGE " << endl; // cout << "START NODE: " << node << " " << relabelFrom << " -> " << relabelTo << endl; // for (auto [k, v]: nodesInSubtree[node]) cout << k << " " << v << " | "; cout << endl; // This case happens when we relabel to the root for multiple nodes. In this case, we've already compressed the relabeling, so we're good. // (Here is an example of a data structure where it's trivial to update things from bototm up, but hard to know what to dfs into top-down). if (!nodesInSubtree[node].count(relabelFrom)) return; // this is correct since we're just locally compressing the sequence, we're not doing anything fancy like passing up the time. // in the brute force version, we'd maintain the entire sequence of relabeled nodes per thing. // but obviously, we can compress all of those, and then only the maximum time (e.g. earliest suffix) matters. ll v = nodesInSubtree[node][relabelFrom]; nodesInSubtree[node].erase(relabelFrom); nodesInSubtree[node][relabelTo] = max(nodesInSubtree[node][relabelTo], v); if (node != parent[node]) change(parent[node], relabelFrom, relabelTo); } // this is a bit... sus. bool query(ll node, ll searchLabel, ll w) { if (node != parent[node] and pw[node] >= w) return query(parent[node], searchLabel, w); // cout << "WTF? " << searchLabel << " " << w << endl; // for (auto [k, v]: nodesInSubtree[node]) cout << k << " " << v << endl; auto it = nodesInSubtree[node].find(searchLabel); if (it != nodesInSubtree[node].end() and it->V >= w) return true; return false; } } std::vector<int> check_validity(int N, std::vector<int> X, std::vector<int> Y, std::vector<int> S, std::vector<int> E, std::vector<int> L, std::vector<int> R) { ll Q = R.size(); vector<vector<pl>> queries(N); std::vector<int> ans(Q); F(i, 0, Q) { queries[R[i]].emplace_back(L[i], i); } vector<vector<pl>> edges(N), edgesPre(N); F(i, 0, X.size()) { edges[max(X[i], Y[i])].emplace_back(X[i], Y[i]); edgesPre[min(X[i], Y[i])].emplace_back(X[i], Y[i]); } // E means u can go from [L, N-1] in the suffix dSU krt::init(N); for (ll i = N-1; i >= 0; --i) for (auto [x, y]: edgesPre[i]) { krt::merge(x, y, i); } // S means u can go from [0, R] in the prefix DSU F(i, 0, N) { parent[i] = i; dsuSet[i] = {i}; } F(right, 0, N) { for (auto &[x, y]: edges[right]) { auto result = merge(x, y); if (result.has_value()) { auto [relabel, nodes] = *result; for (auto x: nodes) { krt::change(x, relabel.V, relabel.K); } } } for (auto &[left, qidx]: queries[right]) { // cout << "Current prefix dsu: " << endl; // F(i, 0, N) cout << find(i) << " "; cout << endl; // cout << "??? " << E[qidx] << " " << S[qidx] << " " << find(S[qidx]) << endl; ans[qidx] = krt::query(S[qidx], find(E[qidx]), left); } } return ans; }

Compilation message (stderr)

werewolf.cpp: In function 'std::vector<int> check_validity(int, std::vector<int>, std::vector<int>, std::vector<int>, std::vector<int>, std::vector<int>, std::vector<int>)':
werewolf.cpp:6:39: warning: comparison of integer expressions of different signedness: 'll' {aka 'int'} and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
    6 | #define F(i, l, r) for (ll i = (l); i < (r); ++i)
      |                                       ^
werewolf.cpp:116:5: note: in expansion of macro 'F'
  116 |     F(i, 0, X.size()) {
      |     ^
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...