Изначально:
1. У корня глубина 0.
Команда ADD:
1. вершина.предок = предок
2. вершина.глубина = предок.глубина + 1
Команда GET:
1. Найти ту вершину, что глубже. Если у одной глубина 5, у другой 7 — подняться от второй на 2.
2. А теперь параллельно и от первой, и от второй вершины поднимаемся вверх на единицу, пока не придём в одну и ту же вершину.
Если хватит памяти — можно устроить какой-то кэш. Мой вариант — кэшировать предков порядка 1,2,4,8…
Чтобы подняться от вершины на 30 единиц…
1. Находим ближайшую степень двойки (16).
2. Если эта степень есть в кэше — просто берём её.
3. Иначе находим максимальную имеющуюся степень (например, 4). Заходим в эту вершину и рекурсивно поднимаемся от неё на 4, потом на 8, заполняя наш кэш.
4. На оставшиеся 14 поднимаемся по тому же алгоритму.
Чтобы найти общего предка двух вершин — у одной глубина 30, у другой 40.
1. От той вершины, у которой 40, поднимаемся на 10 единиц. Алгоритм я привёл.
2. Одинаковые? — тогда понятно.
3. Имеют общего предка? — тогда понятно.
4. Иначе поднимаемся на 1, 2, 4, 8, 16 единиц от каждой из них по указанному алгоритму, каждый из этих шагов при наличии кэша даст O(1). Находим последнюю НЕСОВПАДАЮЩУЮ глубину. Для них повторяем алгоритм.
ВАРИАНТ КЭША ВТОРОЙ. Для вершины глубины 27=11010 кэшировать предков АБСОЛЮТНЫХ (то есть от корня!) глубин 16=1.0000, 24=11.000, 24 :) =110.00, 26=1101.0. Тогда при создании вершины весь кэш достаточно быстро строится на основе кэша вершины-предка.
Чтобы подняться от вершины глубины 27 на расстояние, например, 5, нам нужна абсолютная глубина 27−5=22.
Есть только 24 → действуем так. Выныриваем туда на 24, но там кэш совершенно негодный → а дальше нас проведёт кэш глубины 23. Так поднимаемся на 1 до 23-й и повторяем алгоритм.
Чтобы найти общего предка двух вершин (их глубины, скажем, 27 и 42), точно так же уравниваем глубины. Затем поднимаемся до глубин 16, 24, 24, 26…, пока не найдём несовпадение. Идём в эти несовпадающие вершины, проходим от них к предку и повторяем алгоритм.