結果

問題 No.2337 Equidistant
ユーザー rniya
提出日時 2023-06-02 22:43:25
言語 C++17
(gcc 13.3.0 + boost 1.87.0)
結果
AC  
実行時間 208 ms / 4,000 ms
コード長 7,269 bytes
コンパイル時間 2,047 ms
コンパイル使用メモリ 206,100 KB
最終ジャッジ日時 2025-02-13 19:42:04
ジャッジサーバーID
(参考情報)
judge2 / judge4
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 1
other AC * 28
権限があれば一括ダウンロードができます

ソースコード

diff #
プレゼンテーションモードにする

#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;
}
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
0