lca の問題リストに追加!
問題概要
頂点数 の木と、2 頂点 が与えられる。各 に対して、以下の問いに答えよ。
- パス - と、パス - の両方に含まれる頂点の個数を答えよ
制約
考えたこと
頂点 を始点とする根付き木を作った。そうしたら、あとは色々できる。
ここでは、次のようにした。
- 2 頂点 の LCA を とする
- 2 頂点 の深さの差を答える
コード
#include <bits/stdc++.h> using namespace std; // Run Tree using Graph = vector<vector<int>>; struct RunTree { // id[v][w] := the index of node w in G[v] vector<map<int, int>> id; // num[v][i] := the size of subtree of G[v][i] with parent v vector<vector<long long>> num; // for finding lca vector<vector<int>> parent; vector<int> depth; // constructor RunTree() {} RunTree(const Graph &G, int root = 0) { init(G, root); } // init void init(const Graph &G, int root = 0) { int N = (int)G.size(); id.assign(N, map<int,int>()); num.assign(N, vector<long long>()); for (int v = 0; v < N; ++v) num[v].assign((int)G[v].size(), 0); int V = (int)G.size(); int h = 1; while ((1<<h) < N) ++h; parent.assign(h, vector<int>(N, -1)); depth.assign(N, -1); rec(G, root); for (int i = 0; i+1 < (int)parent.size(); ++i) for (int v = 0; v < V; ++v) if (parent[i][v] != -1) parent[i+1][v] = parent[i][parent[i][v]]; } // size(u, v) := the size of subtree v with parent u long long size(int u, int v) { return num[u][id[u][v]]; } // lca(u, v) int get_lca(int u, int v) { if (depth[u] > depth[v]) swap(u, v); for (int i = 0; i < (int)parent.size(); ++i) if ( (depth[v] - depth[u]) & (1<<i) ) v = parent[i][v]; if (u == v) return u; for (int i = (int)parent.size()-1; i >= 0; --i) { if (parent[i][u] != parent[i][v]) { u = parent[i][u]; v = parent[i][v]; } } return parent[0][u]; } // dist(u, v) long long get_dist(int u, int v) { int lca = get_lca(u, v); return depth[u] + depth[v] - depth[lca]*2; } // get_parent(v, p) := the parent of v directed for p int get_parent(int v, int p) { if (v == p) return -1; int lca = get_lca(v, p); if (lca != v) return parent[0][v]; for (int i = (int)parent.size()-1; i >= 0; --i) { if (parent[i][p] != -1 && depth[parent[i][p]] > depth[v]) { p = parent[i][p]; } } return p; } // rec int rec(const Graph &G, int v, int p = -1, int d = 0) { int p_index = -1; int sum = 1; parent[0][v] = p; depth[v] = d; for (int i = 0; i < (int)G[v].size(); ++i) { int ch = G[v][i]; id[v][ch] = i; if (ch == p) { p_index = i; continue; } int s = rec(G, ch, v, d+1); num[v][i] = s; sum += s; } if (p_index != -1) num[v][p_index] = (int)G.size() - sum; return sum; } }; void CodeQUEEN_D() { int N, S, T; cin >> N >> S >> T; --S, --T; Graph G(N); for (int i = 0; i < N-1; ++i) { int u, v; cin >> u >> v; --u, --v; G[u].push_back(v); G[v].push_back(u); } RunTree rt(G, S); for (int v = 0; v < N; ++v) { int lca = rt.get_lca(v, T); cout << rt.get_dist(lca, v) + 1 << endl; } } int main() { CodeQUEEN_D(); }