Cod sursa(job #2703518)

Utilizator retrogradLucian Bicsi retrograd Data 8 februarie 2021 18:09:23
Problema Lowest Common Ancestor Scor 70
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 2 kb
#include <bits/stdc++.h>

using namespace std;
const int MAXL = 20;

vector<vector<int>> link;   // link[i][j] -> al 2^i-lea stramos al lui j
vector<int> depth;          // adancimea fiecarui nod
vector<vector<int>> graph;  // arborele

void DFS(int node, int par, int dep) {
  // Construiesc stramosii.
  depth[node] = dep;
  link[node][0] = par;
  for (int i = 0; i + 1 < MAXL; ++i) {
    int anc = link[node][i];
    if (anc != -1) link[node][i + 1] = link[anc][i];
  }
  // Apelez recursiv pe fii.
  for (auto vec : graph[node]) {
    if (vec == par) continue;
    DFS(vec, node, dep + 1);
  }
}

int LCA(int a, int b) {
  // Truc de lenesi, ca sa ma asigur 
  // ca a e mai adanc decat b.
  if (depth[a] < depth[b]) 
    swap(a, b);

  // a -> al d-lea stramos al lui a 
  // (ca sa asigur depth[a] == depth[b])
  int d = depth[a] - depth[b];
  for (int i = 0; d; ++i) {
    if (d % 2) a = link[a][i];
    d /= 2;
  }

  // Important sa verific ca nu cumva a == b == LCA
  // (altfel nu e corect, pentru ca la final returnez parent[a])
  if (a == b) return a;

  // Ma duc in sus cat timp a != b
  // Practic, optimizez codul:
  //   while (a != b) a = parent[a], b = parent[b];
  for (int i = MAXL - 1; i >= 0; --i)
    if (link[a][i] != link[b][i]) 
      // avansez 2^i pasi in sus.
      a = link[a][i], b = link[b][i]; 
  
  // assert crapa programul daca conditia nu e adevarata.
  // Nu modifica cu nimic programul, doar e util ca sa mai 
  // reduci din debugging cand ceva nu merge.
  assert(link[a][0] == link[b][0]);
  
  // link[0][a] == al 2^0-lea stramos al lui a == parent[a].
  return link[a][0];
}

int main() {
  ifstream cin("lca.in");
  ofstream cout("lca.out");

  int n, m; cin >> n >> m;
  graph.assign(n, {});
  depth.assign(n, -1);
  link.assign(n, vector<int>(MAXL, -1));

  for (int i = 1; i < n; ++i) {
    int par; cin >> par; --par;
    graph[par].push_back(i);
  }
  DFS(0, -1, 0);

  for (int i = 0; i < m; ++i) {
    int a, b; cin >> a >> b; --a; --b;
    cout << 1 + LCA(a, b) << '\n';
  }

  return 0;
}