#include <iostream>
#include <algorithm>
#include <iomanip>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <vector>
#include <string>
#include <queue>
#include <deque>
#include <list>
#include <set>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <bitset>
#include <random>
#include <complex>
#include <assert.h>

using namespace std;
typedef long long ll;

template<typename T>
inline bool chmin(T& x, T a) {
	if (x >= a) { x = a; return true; }
	return false;
}

template<typename T>
inline bool chmax(T& x, T a) {
	if (x <= a) { x = a; return true; }
	return false;
}

class TreeClass {// グラフ入力を受け取る
public:
	TreeClass() {
		N = 0, root = 0;
		next = NULL;
		weight = NULL;
		parent = NULL;
	}
	~TreeClass() {
		if (weight != NULL) { delete[] weight; }
		if (next != NULL) { delete[] next; }
		if (parent != NULL) { delete[] parent; }
	}

	void activate(int n, int _root = 0) {// 頂点数nのグラフを初期化する。
		N = n;
		root = _root;

		if (weight != NULL) { delete[] weight; }
		if (next != NULL) { delete[] next; }
		edge.clear();

		depth.clear();
		if (parent != NULL) { delete[] parent; }
		distanceTable.clear();

		weight = new ll[N];
		for (int i = 0; i < N; i++) { weight[i] = 1; }
		next = new unordered_map<int, int>[N];

		depth.resize(N);
		parent = new vector<int>[N];
		for (int i = 0; i < N; i++) { parent[i].clear(); }
		distanceTable.resize(N);
	}
	inline void setNodeWeight(int n, ll weight) {// n番のノードの重みをweightに設定
		this->weight[n] = weight;
	}

	inline int getEdgeIndex(int x, int y) {// 辺の組からエッジの番号を得る
		if (next[x].find(y) != next[x].end()) {
			return next[x][y];
		}
		return -1;
	}
	inline void addEdge(int x, int y, ll _weight = 1) {// エッジ追加
		int M = (int)edge.size();
		edge.push_back({ {x,y}, _weight });

		next[x].insert({ y, M });
		next[y].insert({ x, M });

		if (edge.size() == N - 1) {
			{// bfsで根からの深さと距離を得る
				for (int i = 0; i < N; i++) {
					depth[i] = -1;
				}

				queue<pair<int, pair<int, ll>>> q; q.push({ root, {0, 0} });

				while (q.size() > 0) {
					int n = q.front().first;
					int d = q.front().second.first;
					ll w = q.front().second.second;
					q.pop();

					depth[n] = d;
					weight[n] = w;

					for (auto itr = next[n].begin(); itr != next[n].end(); itr++) {
						int m = itr->first;

						if (depth[m] == -1) {
							parent[m].push_back(n);
							q.push({ m, {d + 1, w + edge[itr->second].second} });
						}
					}
				}
			}
			{// ダブリング
				queue<int> q;
				for (int i = 0; i < N; i++) {
					if (i == root) { continue; }
					q.push(i);
				}
				while (q.size() > 0) {
					int n = q.front();
					q.pop();

					int k = parent[n].size() - 1;
					if (depth[n] >= (1 << (k + 1))) {
						parent[n].push_back(parent[parent[n][k]][k]);
						q.push(n);
					}
				}
			}
		}
	}

	inline int LCA(int a, int b) {
		int d = min(depth[a], depth[b]);

		if (depth[a] > d) {
			int k = depth[a] - d;
			for (int i = 0; k > 0; i++) {
				if ((1 << i) & k) {
					k -= (1 << i);
					a = parent[a][i];
				}
			}
		}
		if (depth[b] > d) {
			int k = depth[b] - d;
			for (int i = 0; k > 0; i++) {
				if ((1 << i) & k) {
					k -= (1 << i);
					b = parent[b][i];
				}
			}
		}
		if (a == b) { return a; }

		for (int k = parent[a].size() - 1; k >= 0; k--) {
			if (k < parent[a].size() && k < parent[b].size() && (parent[a][k] != parent[b][k])) {
				a = parent[a][k];
				b = parent[b][k];
			}
		}
		return parent[a][0];
	}

	int N, root;
	ll* weight;// ノードの重み
	unordered_map<int, int>* next;// 各ノードからの行き先とエッジ番号
	vector<pair<pair<int, int>, ll>> edge;// エッジ(頂点ペアと重み)

	vector<int> depth;// 根から見た深さ
	vector<int>* parent;//1番目、2番目、4番目、8番目...の親
	vector<ll> distanceTable;// 根からの距離
};

void bfs(TreeClass &T) {// 幅優先探索
	int N = T.N;
	bool* visited = new bool[N];
	for (int i = 0; i < N; i++) {
		visited[i] = (i == T.root);
	}

	queue<int> q; q.push(T.root);

	while (q.size() > 0) {
		int n = q.front(); q.pop();
		visited[n] = true;

		// ここに各ノードで行う処理を書く

		for (auto itr = T.next[n].begin(); itr != T.next[n].end(); itr++) {
			if (visited[itr->first] == false) {// まだ訪れていなかったら

				// ここに各エッジで行う処理を書く

				q.push(itr->first);
			}
		}
	}

	delete[] visited;
}

bool* dfs_visited = NULL;
void dfs_process_main(TreeClass &T, int n, int depth) {// 深さ優先探索

	// ここに各ノードで行う処理を書く

	for (auto itr = T.next[n].begin(); itr != T.next[n].end(); itr++) {
		int m = itr->first;

		if (dfs_visited[m] == false) {// まだ訪れていなかったら

			// ここに各エッジで行う処理を書く

			dfs_visited[m] = true;
			dfs_process_main(T, m, depth + 1);
			dfs_visited[m] = false;
		}
	}
}
void dfs(TreeClass &T) {// 深さ優先探索
	int N = T.N;
	dfs_visited = new bool[N];
	for (int i = 0; i < N; i++) { dfs_visited[i] = false; }

	dfs_visited[T.root] = true;
	dfs_process_main(T, T.root, 0);

	delete[] dfs_visited;
	dfs_visited = NULL;
}

int main() {
	int N; cin >> N;
	TreeClass T;
	T.activate(N);

	for (int i = 0; i < N; i++) {
		int k; cin >> k;
		for (int j = 0; j < k; j++) {
			int a; cin >> a;
			T.addEdge(i, a);
		}
	}

	int q; cin >> q;
	for (int i = 0; i < q; i++) {
		int a, b; cin >> a >> b;
		int c = T.LCA(a, b);

		cout << c << endl;
	}
	return 0;
}


Measured memory_bytes: 35464