#include <iostream>
#include <vector>
#include <cmath>

using namespace std;


class Tree {
	private:
		vector<vector<size_t> > children;

	public:
		Tree (const size_t &verticesCount) {
			children.resize(verticesCount);
		}

		void addEdge (const size_t &parent, const size_t &child) {
			children[parent].push_back(child);
		}

		void DFS (vector<size_t> &depthList, vector<size_t> &verticesList, vector<size_t> &indexes, const size_t &vertex = 0, const size_t &depth = 0) {
			depthList.push_back(depth);
			verticesList.push_back(vertex);
			indexes[vertex] = verticesList.size() - 1;

			for (const size_t &child: children[vertex]) {
				DFS(depthList, verticesList, indexes, child, depth + 1);
				depthList.push_back(depth);
				verticesList.push_back(vertex);
				indexes[vertex] = verticesList.size() - 1;
			}
		}
};

class SparseTable {
  private:
  	typedef pair<size_t, size_t> Pair;
	vector<vector<Pair> > table;

  public:
	SparseTable (const vector<size_t> &sequence) {
		const size_t length = sequence.size();
		const size_t height = static_cast<size_t>(log2(sequence.size())) + 1;
		table.resize(height);

		for (size_t i = 0; i < length; i ++) {
			table[0].push_back(make_pair(sequence[i], i));
		}

		for (size_t i = 1; i < height; i ++) {
			const size_t currentLength = length - pow(2, i) + 1;
			table[i].resize(currentLength);

			for (size_t j = 0; j < currentLength; j ++) {
				table[i][j] = min<Pair>(table[i - 1][j], table[i - 1][j + pow(2, i - 1)]); 
			}
		}
	}

	Pair RangeMinimumQuery (const size_t left, const size_t right) {
		if (left > right) {
			throw "out of range!";
		}

		const size_t length = right - left + 1;
		const size_t power = static_cast<size_t>(log2(length));
		const size_t flooredLength = pow(2, power);

		const Pair leftValue = table[power][left];
		const size_t padding = length - flooredLength;
		const Pair rightValue = table[power][left + padding];

		return min<Pair>(leftValue, rightValue);
	}
};



int main () {
	size_t verticesCount;
	cin >> verticesCount;

	// Build tree:
	Tree tree(verticesCount);

	for (size_t parent = 0; parent < verticesCount; parent ++) {
		size_t count;
		cin >> count;

		for (size_t j = 0; j < count; j ++) {
			size_t child;
			cin >> child;
			tree.addEdge(parent, child);
		}
	}

	// Count three needed arrays:
	vector<size_t> depthList;
	vector<size_t> verticesList;
	vector<size_t> indexes(verticesCount);
	tree.DFS(depthList, verticesList, indexes);

	/*for (const size_t &el: depthList)
		cout << el << " ";
	cout << endl;

	for (const size_t &el: verticesList)
		cout << (el + 1) << " ";
	cout << endl;

	for (const size_t &el: indexes)
		cout << el << " ";
	cout << endl;*/

	// Prepare Sparse table for solving RMQ:
	SparseTable sparseTable(depthList);

	size_t queriesCount;
	cin >> queriesCount;

	// Processing queries:
	for (size_t i = 0; i < queriesCount; i ++) {
		size_t firstVertex, secondVertex;
		cin >> firstVertex >> secondVertex;
		const size_t firstIndex = indexes[firstVertex];
		const size_t secondIndex = indexes[secondVertex];
		const size_t minIndex = min<size_t>(firstIndex, secondIndex);
		const size_t maxIndex = max<size_t>(firstIndex, secondIndex);
		const size_t index = sparseTable.RangeMinimumQuery(minIndex, maxIndex).second;
		const size_t vertex = verticesList[index];
		cout << (vertex) << endl;
	}

	return 0;
}



Measured memory_bytes: 67920