제출 #400958

#제출 시각아이디문제언어결과실행 시간메모리
400958HegdahlInside information (BOI21_servers)C++17
100 / 100
2713 ms280196 KiB
#pragma GCC optimize("O3") #include <bits/stdc++.h> #include <ext/pb_ds/assoc_container.hpp> #include <ext/pb_ds/tree_policy.hpp> #define ar array using namespace __gnu_pbds; using namespace std; using iset = tree<ar<int, 2>, null_type, less<ar<int, 2>>, rb_tree_tag, tree_order_statistics_node_update>; const int mxN = 120'000; const int INF = 1e9; vector<ar<int, 2>> g[mxN]; int cut[mxN], sz[mxN]; int dfs1(int cur, int prv) { sz[cur] = 1; for (auto [nxt, t] : g[cur]) { if (cut[nxt]) continue; if (nxt == prv) continue; sz[cur] += dfs1(nxt, cur); } return sz[cur]; } vector<int> kids[mxN]; int find_centroid(int cur, int prv, int total) { for (auto [nxt, t] : g[cur]) { if (cut[nxt]) continue; if (nxt == prv) continue; if (2*sz[nxt] > total) return find_centroid(nxt, cur, total); } // this is centroid cut[cur] = 1; if (prv != -1 && !cut[prv]) dfs1(prv, -1); for (auto [nxt, t] : g[cur]) { if (cut[nxt]) continue; kids[cur].push_back(find_centroid(nxt, -1, sz[nxt])); } return cur; } int clvl[mxN]; vector<int> cent_anc[mxN]; iset branches_start[mxN]; void set_anc(int anc, int cur, int prv) { cent_anc[cur].push_back(anc); for (auto [nxt, t] : g[cur]) { if (cut[nxt]) continue; if (nxt == prv) continue; set_anc(anc, nxt, cur); } } gp_hash_table<int, int> out_ws[mxN], in_ws[mxN], path_end[mxN]; void init_reach_out(int root, int bw, int cur, int prv, int w) { out_ws[root][cur] = bw; path_end[root][cur] = w; for (auto [nxt, t] : g[cur]) { if (cut[nxt]) continue; if (nxt == prv) continue; if (t < w) continue; init_reach_out(root, bw, nxt, cur, t); } } void init_reach_in(int root, int bw, int cur, int prv, int w) { in_ws[root][cur] = bw; for (auto [nxt, t] : g[cur]) { if (cut[nxt]) continue; if (nxt == prv) continue; if (t > w) continue; init_reach_in(root, bw, nxt, cur, t); } } void init_centroid(int cur, int d) { clvl[cur] = d; for (int nxt : kids[cur]) init_centroid(nxt, d+1); cent_anc[cur].push_back(cur); for (auto [nxt, t] : g[cur]) { if (cut[nxt]) continue; set_anc(cur, nxt, -1); } cut[cur] = 0; out_ws[cur][cur] = INF; in_ws[cur][cur] = -INF; path_end[cur][cur] = -INF; for (auto [nxt, t] : g[cur]) { if (cut[nxt]) continue; init_reach_out(cur, t, nxt, cur, t); init_reach_in(cur, t, nxt, cur, t); } } bool qry(int i, int j, int t) { int ci = 0; int cj = 0; while (cent_anc[i][ci] != cent_anc[j][cj]) { if (clvl[cent_anc[i][ci]] > clvl[cent_anc[j][cj]]) ++ci; else if (clvl[cent_anc[j][cj]] > clvl[cent_anc[i][ci]]) ++cj; else ++ci, ++cj; } int lca = cent_anc[i][ci]; auto in_it = in_ws[lca].find(j); auto out_it = out_ws[lca].find(i); if (in_it == in_ws[lca].end()) return false; if (out_it == out_ws[lca].end()) return false; if (in_it->second > t) return false; if (in_it->second > out_it->second) return false; if (path_end[lca][i] > t) return false; return true; } int count_reachable(int i, int hi) { int ans = 0; for (int root : cent_anc[i]) { auto reach_it = in_ws[root].find(i); if (reach_it == in_ws[root].end()) continue; int lo = reach_it->second; if (lo > hi) continue; ++ans; int here = (int)branches_start[root].size(); if (here) { if (lo >= 0) here -= (int)branches_start[root].order_of_key({lo, INF}); if (here < 0) here = 0; } ans += here; } return ans; } int brute_reachable(int i, int t, int n) { int ans = 0; for (int j = 0; j < n; ++j) ans += qry(j, i, t); return ans; } int main() { ios::sync_with_stdio(0);cin.tie(0); int n, q; cin >> n >> q; vector<ar<int, 3>> qs; vector<ar<int, 2>> cs; for (int t = 0; t < n+q-1; ++t) { char c; cin >> c; if (c == 'S') { int i, j; cin >> i >> j; --i, --j; g[i].push_back({j, t}); g[j].push_back({i, t}); } else if (c == 'Q') { int i, j; cin >> i >> j; --i, --j; qs.push_back({t, i, j}); } else if (c == 'C') { int i; cin >> i; --i; cs.push_back({t, i}); } else assert(0); } dfs1(0, -1); int root = find_centroid(0, -1, sz[0]); for (int i = 0; i < n; ++i) assert(cut[i]); init_centroid(root, 0); for (int i = 0; i < n; ++i) assert(!cut[i]); vector<pair<int, string>> ans; ans.reserve(q); for (auto [t, i, j] : qs) ans.push_back({t, qry(i, j, t)?"yes":"no"}); vector<ar<int, 4>> upd_q; for (int i = 0; i < n; ++i) { for (int rt : cent_anc[i]) { if (i == rt) continue; auto out_it = out_ws[rt].find(i); if (out_it == out_ws[rt].end()) continue; int w_start = out_it->second; int w_end = path_end[rt][i]; upd_q.push_back({w_end, w_start, rt, i}); } } int upd_i = 0; sort(upd_q.begin(), upd_q.end()); for (auto [t, i] : cs) { while (upd_i < (int)upd_q.size() && upd_q[upd_i][0] <= t) { auto [ut, w, rt, nd] = upd_q[upd_i++]; branches_start[rt].insert({w, nd}); } ans.push_back({t, to_string(count_reachable(i, t))}); } sort(ans.begin(), ans.end()); for (auto &[t, s] : ans) cout << s << '\n'; }
#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...
#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...