#include <cstdio> #include <vector> using namespace std; // Τα παιδιά του κόμβου. vector<vector<long>> adj; // Το βάθος ενός κόμβου στο δένδρο και ο πατέρας του. vector<long> d, par; // Όπως ορίστηκαν πριν. vector<long> idx; vector<vector<long>> v; // Αν η ακμή που συνδέει το κόμβο με τον πατέρα του είναι heavy. vector<bool> is_heavy; // Το ID του τελευταίου μονοπατιού που δημιουργήσαμε. long cur_heavy_id; long compute_hld(long u, long par_depth) { d[u] = par_depth + 1; // Για τα φύλλα ξεκινάμε ένα καινούργιο heavy μονοπάτι. if (adj[u].size() == 0) { heavy_path_id[u] = ++cur_heavy_id; v[heavy_path_id[u]].push_back(u); idx[u] = 0; return 1; } // Δημιουργούμε αναδρομικά τα μονοπάτια των παιδιών. // Βρίσκουμε το παιδί με το μεγαλύτερο υποδένδρο και επεκτείνουμε // το δικό του μονοπάτι. long subtree_size = 0, max_subtree_size = 0, cur_heavy_edge; for (auto v : adj[u]) { long cur_subtree_size = compute_hld(v, d[u]); subtree_size += cur_subtree_size; if (cur_subtree_size > max_subtree_size) { max_subtree_size = cur_subtree_size; cur_heavy_edge = v; } } // Μαρκάρουμε την ακμή ως heavy και ανανεώνουμε τους πίνακες. is_heavy[cur_heavy_edge] = true; long path_id = heavy_path_id[cur_heavy_edge]; heavy_path_id[u] = path_id; idx[u] = v[path_id].size(); v[path_id].push_back(u); return subtree_size; } long find_kth_ancestor(long x, long k) { while (k > 0) { if (is_heavy[x]) { if (k + idx[x] < v[heavy_path_id[x]].size()) { // (1) Πρόγονος εντός heavy μονοπατιού return v[heavy_path_id[x]][k + idx[x]]; } else { // (2) Πρόγονος εκτός heavy μονοπατιού k -= (v[heavy_path_id[x]].size() - idx[x] - 1); x = v[heavy_path_id[x]].back(); } } else { // (3) light ακμή x = par[x]; --k; } } return x; } long find_lca(long a, long b) { while (a != b) { if (heavy_path_id[a] == heavy_path_id[b]) { // Αφού είναι στο ίδιο heavy μονοπάτι, επιστρέφουμε // αυτόν που είναι ψηλότερα. return d[a] < d[b] ? a : b; } long a_next = is_heavy[a] ? v[heavy_path_id[a]].back() : par[a]; long b_next = is_heavy[b] ? v[heavy_path_id[b]].back() : par[b]; // Μετακινούμε τον χαμηλότερο. if (d[a_next] > d[b_next]) a = a_next; else b = b_next; } return a; } void clear() { adj.clear(); d.clear(); par.clear(); v.clear(); idx.clear(); is_heavy.clear(); heavy_path_id.clear(); cur_heavy_id = 0; } void reset(long N) { par.resize(N+1); adj.resize(N+1); d.resize(N+1); v.resize(N+1); idx.resize(N+1); is_heavy.resize(N+1); heavy_path_id.resize(N+1); } int main() { long T; scanf("%ld", &T); for (long case_id = 1; case_id <= T; ++case_id) { clear(); long N; scanf("%ld", &N); reset(N); for (long i = 1; i <= N; ++i) { long m; scanf("%ld", &m); for (long j = 0; j < m; ++j) { long k; scanf("%ld", &k); adj[i].push_back(k); par[k] = i; } } // Find root. long root; for (long i = 1; i <= N; ++i) { if (par[i] == 0) { root = i; break; } } // Pre-process. compute_hld(root, 0); // Answer queries. long Q; scanf("%ld", &Q); printf("Case %ld:\n", case_id); while (Q--) { long a, b; scanf("%ld%ld", &a, &b); printf("%ld\n", find_kth_ancestor(a, b)); } } return 0; }