Родословная: предки и потомки
Вы решили задачу. Теперь можно сравнить подходы.
Предок содержит всё поддерево потомка; это можно проверить временами обхода.
Авторский разбор для локальной версии на основе условия задачи. Это не выгрузка чужих посылок и не официальное решение исходного сайта.
Ваше принятое решение
Рекомендуемое решение: Интервалы итеративного обхода
Время входа любой вершины поддерева попадает в интервал от входа до выхода его корня. Явный стек обрабатывает глубокие цепочки без рекурсии. Предок здесь строгий: одинаковые имена дают 0. Для единственной вершины имя восстанавливается из запросов.
n = int(input())
parent = {}
children = {}
for _ in range(n - 1):
child, ancestor = input().split()
parent[child] = ancestor
children.setdefault(ancestor, []).append(child)
children.setdefault(child, [])
q = int(input())
queries = [input().split() for _ in range(q)]
for a, b in queries:
children.setdefault(a, [])
children.setdefault(b, [])
enter, leave = {}, {}
if children:
root = next(name for name in children if name not in parent)
stack = [(root, False)]
clock = 0
while stack:
name, exiting = stack.pop()
if exiting:
leave[name] = clock
else:
enter[name] = clock
clock += 1
stack.append((name, True))
for child in children[name]:
stack.append((child, False))
def ancestor(a, b):
return a != b and enter[a] <= enter[b] < leave[a]
for a, b in queries:
print(1 if ancestor(a, b) else 2 if ancestor(b, a) else 0)
Время: Ожидаемое O(n + q) без учёта длины имён. Память: O(n + q) записей, включая сохранённые запросы.
Другой способ: Подъём по родителям
Ищем первое имя среди строгих предков второго, затем проверяем обратное направление. Подготовка проста, но каждый запрос может пройти всю высоту дерева.
n = int(input())
parent = {}
children = {}
for _ in range(n - 1):
child, ancestor = input().split()
parent[child] = ancestor
children.setdefault(ancestor, []).append(child)
children.setdefault(child, [])
q = int(input())
queries = [input().split() for _ in range(q)]
for a, b in queries:
children.setdefault(a, [])
children.setdefault(b, [])
def ancestor(a, b):
while b in parent:
b = parent[b]
if b == a:
return True
return False
for a, b in queries:
print(1 if ancestor(a, b) else 2 if ancestor(b, a) else 0)
Время: Ожидаемое O(n + q(h + 1)), h — высота. Память: O(n + q) записей.
На что обратить внимание
- Не путайте ответ 1 (первое имя — предок) и 2.
- Порядок строк ввода не обязан совпадать с обходом дерева.
Рекомендация учитывает сложность и читаемость для этой задачи. Единственного самого быстрого решения для всех размеров входа и всех компьютеров может не быть.