結果
問題 | No.2337 Equidistant |
ユーザー | rniya |
提出日時 | 2023-06-02 22:43:25 |
言語 | C++17 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 306 ms / 4,000 ms |
コード長 | 7,269 bytes |
コンパイル時間 | 2,639 ms |
コンパイル使用メモリ | 213,656 KB |
実行使用メモリ | 31,744 KB |
最終ジャッジ日時 | 2024-06-09 00:27:43 |
合計ジャッジ時間 | 9,932 ms |
ジャッジサーバーID (参考情報) |
judge4 / judge5 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 2 ms
5,248 KB |
testcase_01 | AC | 2 ms
5,376 KB |
testcase_02 | AC | 2 ms
5,376 KB |
testcase_03 | AC | 2 ms
5,376 KB |
testcase_04 | AC | 2 ms
5,376 KB |
testcase_05 | AC | 2 ms
5,376 KB |
testcase_06 | AC | 3 ms
5,376 KB |
testcase_07 | AC | 4 ms
5,376 KB |
testcase_08 | AC | 4 ms
5,376 KB |
testcase_09 | AC | 3 ms
5,376 KB |
testcase_10 | AC | 3 ms
5,376 KB |
testcase_11 | AC | 278 ms
19,840 KB |
testcase_12 | AC | 275 ms
19,840 KB |
testcase_13 | AC | 281 ms
19,840 KB |
testcase_14 | AC | 282 ms
19,712 KB |
testcase_15 | AC | 279 ms
19,840 KB |
testcase_16 | AC | 265 ms
19,840 KB |
testcase_17 | AC | 280 ms
19,840 KB |
testcase_18 | AC | 276 ms
19,840 KB |
testcase_19 | AC | 276 ms
19,840 KB |
testcase_20 | AC | 273 ms
19,840 KB |
testcase_21 | AC | 233 ms
31,744 KB |
testcase_22 | AC | 182 ms
20,388 KB |
testcase_23 | AC | 239 ms
20,608 KB |
testcase_24 | AC | 306 ms
27,776 KB |
testcase_25 | AC | 266 ms
20,480 KB |
testcase_26 | AC | 292 ms
27,648 KB |
testcase_27 | AC | 256 ms
20,608 KB |
testcase_28 | AC | 239 ms
20,480 KB |
ソースコード
#include <bits/stdc++.h> #ifdef LOCAL #include <debug.hpp> #else #define debug(...) void(0) #endif struct HeavyLightDecomposition { std::vector<std::vector<int>> G; // child of vertex v on heavy edge is G[v].front() if it is not parent of v int n, time; std::vector<int> par, // parent of vertex v sub, // size of subtree whose root is v dep, // distance bitween root and vertex v head, // vertex that is the nearest to root on heavy path of vertex v tree_id, // id of tree vertex v belongs to vertex_id, // id of vertex v (consecutive on heavy paths) vertex_id_inv; // vertex_id_inv[vertex_id[v]] = v HeavyLightDecomposition(int n) : G(n), n(n), time(0), par(n, -1), sub(n), dep(n, 0), head(n), tree_id(n, -1), vertex_id(n, -1), vertex_id_inv(n) {} void add_edge(int u, int v) { assert(0 <= u and u < n); assert(0 <= v and v < n); G[u].emplace_back(v); G[v].emplace_back(u); } void build(std::vector<int> roots = {0}) { int tree_id_cur = 0; for (int& r : roots) { assert(0 <= r and r < n); dfs_sz(r); head[r] = r; dfs_hld(r, tree_id_cur++); } assert(time == n); for (int v = 0; v < n; v++) vertex_id_inv[vertex_id[v]] = v; } int idx(int v) const { return vertex_id[v]; } int la(int v, int k) const { assert(0 <= v and v < n); assert(0 <= k and k <= dep[v]); while (1) { int u = head[v]; if (vertex_id[v] - k >= vertex_id[u]) return vertex_id_inv[vertex_id[v] - k]; k -= vertex_id[v] - vertex_id[u] + 1; v = par[u]; } } int lca(int u, int v) const { assert(0 <= u and u < n); assert(0 <= v and v < n); assert(tree_id[u] == tree_id[v]); for (;; v = par[head[v]]) { if (vertex_id[u] > vertex_id[v]) std::swap(u, v); if (head[u] == head[v]) return u; } } int jump(int s, int t, int i) const { assert(0 <= s and s < n); assert(0 <= t and t < n); assert(0 <= i); if (tree_id[s] != tree_id[t]) return -1; if (i == 0) return s; int p = lca(s, t), d = dep[s] + dep[t] - 2 * dep[p]; if (d < i) return -1; if (dep[s] - dep[p] >= i) return la(s, i); return la(t, d - i); } int distance(int u, int v) const { assert(0 <= u and u < n); assert(0 <= v and v < n); assert(tree_id[u] == tree_id[v]); return dep[u] + dep[v] - 2 * dep[lca(u, v)]; } template <typename F> void query_path(int u, int v, const F& f, bool vertex = false) const { assert(0 <= u and u < n); assert(0 <= v and v < n); assert(tree_id[u] == tree_id[v]); int p = lca(u, v); for (auto& e : ascend(u, p)) f(e.second, e.first + 1); if (vertex) f(vertex_id[p], vertex_id[p] + 1); for (auto& e : descend(p, v)) f(e.first, e.second + 1); } template <typename F> void query_path_noncommutative(int u, int v, const F& f, bool vertex = false) const { assert(0 <= u and u < n); assert(0 <= v and v < n); assert(tree_id[u] == tree_id[v]); int p = lca(u, v); for (auto& e : ascend(u, p)) f(e.first + 1, e.second); if (vertex) f(vertex_id[p], vertex_id[p] + 1); for (auto& e : descend(p, v)) f(e.first, e.second + 1); } template <typename F> void query_subtree(int u, const F& f, bool vertex = false) const { assert(0 <= u and u < n); f(vertex_id[u] + !vertex, vertex_id[u] + sub[u]); } private: void dfs_sz(int v) { sub[v] = 1; if (!G[v].empty() and G[v].front() == par[v]) std::swap(G[v].front(), G[v].back()); for (int& u : G[v]) { if (u == par[v]) continue; par[u] = v; dep[u] = dep[v] + 1; dfs_sz(u); sub[v] += sub[u]; if (sub[u] > sub[G[v].front()]) std::swap(u, G[v].front()); } } void dfs_hld(int v, int tree_id_cur) { vertex_id[v] = time++; tree_id[v] = tree_id_cur; for (int& u : G[v]) { if (u == par[v]) continue; head[u] = (u == G[v][0] ? head[v] : u); dfs_hld(u, tree_id_cur); } } std::vector<std::pair<int, int>> ascend(int u, int v) const { // [u, v), v is ancestor of u std::vector<std::pair<int, int>> res; while (head[u] != head[v]) { res.emplace_back(vertex_id[u], vertex_id[head[u]]); u = par[head[u]]; } if (u != v) res.emplace_back(vertex_id[u], vertex_id[v] + 1); return res; } std::vector<std::pair<int, int>> descend(int u, int v) const { // (u, v], u is ancestor of v if (u == v) return {}; if (head[u] == head[v]) return {{vertex_id[u] + 1, vertex_id[v]}}; auto res = descend(u, par[head[v]]); res.emplace_back(vertex_id[head[v]], vertex_id[v]); return res; } }; using namespace std; typedef long long ll; #define all(x) begin(x), end(x) constexpr int INF = (1 << 30) - 1; constexpr long long IINF = (1LL << 60) - 1; constexpr int dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1}; template <class T> istream& operator>>(istream& is, vector<T>& v) { for (auto& x : v) is >> x; return is; } template <class T> ostream& operator<<(ostream& os, const vector<T>& v) { auto sep = ""; for (const auto& x : v) os << exchange(sep, " ") << x; return os; } template <class T, class U = T> bool chmin(T& x, U&& y) { return y < x and (x = forward<U>(y), true); } template <class T, class U = T> bool chmax(T& x, U&& y) { return x < y and (x = forward<U>(y), true); } template <class T> void mkuni(vector<T>& v) { sort(begin(v), end(v)); v.erase(unique(begin(v), end(v)), end(v)); } template <class T> int lwb(const vector<T>& v, const T& x) { return lower_bound(begin(v), end(v), x) - begin(v); } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int N, Q; cin >> N >> Q; HeavyLightDecomposition G(N); for (int i = 0; i < N - 1; i++) { int A, B; cin >> A >> B; G.add_edge(--A, --B); } G.build(); auto query = [&](int S, int T) -> int { if (G.dep[S] > G.dep[T]) swap(S, T); int d = G.distance(S, T); if (d & 1) return 0; int p = G.lca(S, T); if (p == S) { int u = G.jump(T, S, d / 2), v = G.jump(T, S, d / 2 - 1); return G.sub[u] - G.sub[v]; } else if (G.distance(p, T) > d / 2) { int u = G.jump(T, S, d / 2), v = G.jump(T, S, d / 2 - 1); return G.sub[u] - G.sub[v]; } else { assert(G.distance(p, T) == d / 2); int u = G.jump(T, p, d / 2 - 1), v = G.jump(S, p, d / 2 - 1); return N - G.sub[u] - G.sub[v]; } }; for (; Q--;) { int S, T; cin >> S >> T; cout << query(--S, --T) << '\n'; } return 0; }