Найменший спільний предок — Вікіпедія

Найменший спільний предок вершин та в кореневому дереві — найвіддаленіша від кореня дерева вершина, яка лежить на обидвох шляхах від та до кореня дерева, тобто є предком обидвох вершин.

Алгоритми[ред. | ред. код]

Опис алгоритму методу двійкового підйому[ред. | ред. код]

Метод двійкового підйому — онлайн алгоритм вирішення задачі пошуку найменшого спільного предка. Він не використовує діапазон мінімального запиту[en] і заснований на методі динамічного програмування.

Як і більшість online алгоритмів, цей метод спочатку робить підрахунок offline, а потім це використовує для відповіді на запити.

Підрахунок offline[ред. | ред. код]

Підрахунок offline полягає в тому, щоб порахувати функцію:  — вершина, у яку ми прийдемо, пройшовши уверх ребер з вершини , при чому, якщо ми прийшли в корінь дерева, то там і залишаємося. Для цього спочатку запустимо обхід в глибину з кореня і для кожної вершини запишемо номер її батька та глибину вершини в підвішеному дереві . Якщо корінь — , то , тоді для функції є рекурентна формула :

Для того, щоб відповідати на запити, нам потрібні тільки ті значення , для яких , бо для великих значень дорівнюватиме значенню кореня.

Всього станів динаміки , де кількість вершин у дереві. Кожний стан рахується за , тому загальна складність .

Відповіді на запити[ред. | ред. код]

Відповідати на запити будемо за час . Спочатку помітимо, якщо вершина для деяких та то . Тому, якщо , то пройдемо від вершини на кроків уверх, це і буде нове значення , яке ми можемо порахувати за . Число ми можемо записати у двійковій системі числення як :

і для всіх пройти вверх послідовно із вершини у вершину .

Далі вважаємо, що .

Якщо , то відповідь на запит .

Інакше, якщо , то знайдемо такі вершини та , що та . Тоді відповіддю на запит буде .

Щоб знайти вершини та , спочатку ініціалізуємо та , та знаходитимемо таке максимальне , що . Тоді піднімемося вгору на кроків угору з обидвох вершин, та повторимо цю процедуру. Якщо такого знайти не можна, то знайдені вершини і є тими, які нам потрібно знайти, бо .

Оцінимо час роботи алгоритму.

Помітимо, що знайдені строго спадають, оскільки, по-перше, щоразу ми знаходимо максимальне значення , а по-друге, два рази поспіль одне й те саме значення отримати не можемо, бо і ми тоді б взяли , тому можна перебирати всього значень в порядку спадання. Отже, складність відповіді .

Псевдокод[ред. | ред. код]

  function preprocess():      int[] p = dfs(0)      for i = 1 to n         dp[i][0] = p[i]      for j = 1 to log(n)         for i = 1 to n            dp[i][j] = dp[dp[i][j - 1]][j - 1]      int lca(int v, int u):      if d[v] > d[u]         swap(v, u)      for i = log(n) downto 0         if d[u] - d[v]             u = dp[u][i]      if v == u         return v      for i = log(n) downto 0         if dp[v][i] != dp[u][i]            v = dp[v][i]            u = dp[u][i]      return p[v] 

Література[ред. | ред. код]

  • Aho, Alfred; Hopcroft, John; Ullman, Jeffrey (1973), On finding lowest common ancestors in trees, Proc. 5th ACM Symp. Theory of Computing (STOC), с. 253—265, doi:10.1145/800125.804056.
  • Наименьший общий предок. Нахождение за O (log N) (метод двоичного подъёма)
  • Метод двоичного подъема

Див. також[ред. | ред. код]

Примітки[ред. | ред. код]

  1. Алгоритм Фарака-Колтона и Бендера. Архів оригіналу за 1 грудня 2018.