Advertisement
ashmelev

LCA

Feb 19th, 2019
212
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 3.00 KB | None | 0 0
  1. #include <iostream>
  2. #include <vector>
  3.  
  4. using namespace std;
  5.  
  6. const int MAXN = 100000; // максимальное количество вершин
  7. const int MAXK = 20;     // степень двойки, до которой считаем подъем
  8.  
  9. int n;                   // количество вершин
  10. vector<int> v[MAXN];     // список смежности для каждой вершины
  11. int p[MAXN];             // непосредственный предок (родитель)
  12. int pr[MAXN][MAXK];      // массив переходов по степеням двойки
  13. int t1[MAXN];            // время входа в вершину
  14. int t2[MAXN];            // время выхода из вершины
  15. int ct;                  // текущее время
  16.  
  17. void dfs(int x, int p) {
  18.     // x - текущая вершина, p - её родитель
  19.     t1[x] = ct++;
  20.     ::p[x] = p;  // сохраняем предка в глобальном массиве
  21.  
  22.     for (int y : v[x]) {
  23.         if (y == p)
  24.             continue;
  25.         dfs(y, x);
  26.     }
  27.  
  28.     t2[x] = ct++;
  29. }
  30.  
  31. // функция считает переходы по степеням двойки
  32. void calcBinary() {
  33.     for (int i = 0; i < n; i++)
  34.         pr[i][0] = p[i];  // подъем на 2^0 - это переход в непосредственного предка
  35.  
  36.     for (int k = 1; k < MAXK; k++)
  37.         for (int x = 0; x < n; x++) {
  38.             int y = pr[x][k - 1];  // поднялись на 2^(k-1)
  39.             int z = pr[y][k - 1];  // поднялись еще на 2^(k-1)
  40.             pr[x][k] = z;          // сохраняем результат - поднялись в сумме на 2^k
  41.         }
  42. }
  43.  
  44. // функция проверяет, является ли x предком y (т.е. лежит ли y в поддереве вершины x)
  45. bool checkParent(int x, int y) {
  46.     return t1[x] <= t1[y] && t2[x] >= t2[y];
  47. }
  48.  
  49. // функция находит наименьшего общего предка
  50. int lca(int x, int y) {
  51.     if (checkParent(x, y))  // если x уже предок y, то ответ x
  52.         return x;
  53.  
  54.     for (int k = MAXK - 1; k >= 0; k--) {
  55.         int z = pr[x][k];  // поднимаемся от x на 2^k
  56.         if (!checkParent(z, y))
  57.             x = z;  // если мы все еще не стали предком y, то сохраняем этот переход
  58.     }
  59.  
  60.     return p[x];  // в итоге мы оказались на одну вершину ниже lca,
  61.                   // поэтому возвращаем ее предка
  62. }
  63.  
  64. int main() {
  65.     cin >> n;
  66.     for (int i = 0; i < n - 1; i++) {
  67.         // считываем ребра
  68.         int a, b;
  69.         cin >> a >> b;
  70.         v[a].push_back(b);
  71.         v[b].push_back(a);
  72.     }
  73.  
  74.     dfs(0, 0);     // считаем массивы t1, t2, p
  75.     calcBinary();  // считаем массив pr
  76.  
  77.     int q;
  78.     cin >> q;
  79.     for (int i = 0; i < q; i++) {
  80.         // отвечаем на запросы - для пары вершин найти общего предка
  81.         int a, b;
  82.         cin >> a >> b;
  83.         cout << lca(a, b) << endl;
  84.     }
  85. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement