Cod sursa(job #3174425)

Utilizator BuruianaRaresAndreiBuruiana Rares Andrei BuruianaRaresAndrei Data 24 noiembrie 2023 19:13:20
Problema Lowest Common Ancestor Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.1 kb
#include <fstream>
#include <vector>
#include <list>
#include <cmath>

using namespace std;

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

int num_nodes, queries;
list<int> links[100002];
int f_app[100002];
pair<int, int> et[200002]; int pos = 1;
pair<int, int> rmq[18][100002];

void euler_tour(int node, int grade);
int range_minimum_query(int node1, int node2);

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(nullptr);

  cin >> num_nodes >> queries;
  for(int i = 2 ; i <= num_nodes; i++) {
    int node;
    cin >> node;
    links[node].push_back(i);
  }
  //euler tour using dfs
  euler_tour(1, 0);
  pos--;

  //test: show the euler euler tour
  /*
  for(int i = 1; i <= pos; i++) {
    cout << et[i].first << ' ';
  }
  cout << '\n';
  for(int i = 1; i <= pos; i++) {
    cout << et[i].second << ' ';
  }
  cout << '\n' << '\n';
  */

  //test: show f_app
  /*
  for(int i = 1; i <= num_nodes; i++) {
    cout << f_app[i] << ' ';
  }
  cout << '\n' << '\n';
  */

  //form the range minimum query
  for(int i = 1; i <= pos; i++) {
    rmq[0][i].first = et[i].first;
    rmq[0][i].second = et[i].second;
  }
  for(int i = 2; i <= pos; i *= 2) {
    for(int j = 1; j <= pos - i + 1; j++) {
      //.second will be the minimum between the 2 pairs above
      //.first will be the grade of the number selected
      int line = log2(i);
      if(rmq[line - 1][j].second < rmq[line - 1][j + i / 2].second) {
        rmq[line][j].first = rmq[line - 1][j].first;
        rmq[line][j].second = rmq[line - 1][j].second;
      }
      else {
        rmq[line][j].first = rmq[line - 1][j + i / 2].first;
        rmq[line][j].second = rmq[line - 1][j + i / 2].second;
      }
    }
  }


  //test: show the rmq
  /*
  for(int i = 0; i <= log2(pos); i++) {
    for(int j = 1; j <= pos - (1 << i) + 1; j++) {
      cout << rmq[i][j].first << ' ';
    }
    cout << '\n';
  }
  cout << '\n';
  */

  //answer the queries
  while(queries--) {
    int node1, node2;
    cin >> node1 >> node2;
    cout << range_minimum_query(min(f_app[node1], f_app[node2]), max(f_app[node1], f_app[node2])) << '\n';
  }

  return 0;
}

void euler_tour(int node, int grade) {
  et[pos].first = node;
  et[pos].second = grade;
  pos++;
  if(f_app[node] == 0) {
    f_app[node] = pos - 1;
  }
  for(auto link : links[node]) {
    euler_tour(link, grade + 1);
    et[pos].first = node;
    et[pos].second = grade;
    pos++;
  }
}

int range_minimum_query(int app_node1, int app_node2) {
  pair<int, int> ans = make_pair(-1, -1); int crt = app_node1;
  int length = app_node2 - app_node1 + 1;
  //return length;
  /*
  for(int i = 0; i <= log2(length); i++) {
    if(length & (1 << i)) {
      if(ans == make_pair(-1, -1)) {
        ans = rmq[i][crt];
      }
      else {
        if(rmq[i][crt].second < ans.second) {
          ans = rmq[i][crt];
        }
      }
      //cout << length << ' ' << (1 << i) << '\n';
      crt += (1 << i);
    }
  }
  */
  ans = rmq[(int)log2(length)][app_node1];
  if(rmq[(int)log2(length)][app_node2 - (1 << ((int)log2(length) - 1))].second < ans.second)
    ans = rmq[(int)log2(length)][app_node2 - (1 << ((int)log2(length) - 1))];
  return ans.first;
}