Cod sursa(job #2606508)

Utilizator avtobusAvtobus avtobus Data 27 aprilie 2020 21:45:55
Problema Lowest Common Ancestor Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 2.97 kb
#include <stdio.h>
#include <bits/stdc++.h>

#define rep(i, n) for(int i = 0; i < (int)(n); i++)

using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
const int INF = 0x3f3f3f3f;

ifstream fin ("lca.in");
ofstream fout ("lca.out");
const int Nmax = 100555;

vi Cop[Nmax]; // for each vertex keeps a list of children
vi Epath; // vertices in the Euler path
vi Lvl;   // corresponding level of the vertex in the Euler path; // will run RMQ on Lvl
vi H(Nmax, -1);     // where in the euler path is the first occurence of a given vertex;

void dfs(int nod, int lvl) {
  if (H[nod] == -1) { H[nod] = Epath.size(); }
  Epath.push_back(nod);
  Lvl.push_back(lvl);
  for(auto c: Cop[nod]) {
    dfs(c, lvl+1);
    Epath.push_back(nod);
    Lvl.push_back(lvl);
  }
}

int main(void) {
  // freopen("lca.in", "r", stdin);
  std::ios_base::sync_with_stdio(false);
  std::cin.tie(NULL);
  int N, M, a, b;
  fin >> N >> M;
  for(int i = 1; i < N; i++) {
    fin >> a;
    --a;
    Cop[a].push_back(i);
  }

  // dfs to construct the Euler representation on which we will be running rmq;
  dfs(0, 0);
  // cout << Epath.size() << " " << Lvl.size() << endl;
  // for(auto e: Epath) { cout << e+1 << ' '; } cout << endl;
  // for(auto l: Lvl) { cout << l << ' '; } cout << endl;
  // for(int i = 0; i < N; i++) {
  //   cout << i << ":\t" << H[i] << endl;
  // }

  // pre-process rmq;
  int rmqN = Lvl.size();
  vi lg(rmqN+1, 0);
  for(int n = 2; n <= rmqN; n++) { lg[n] = lg[n/2] + 1; }
  // cout << string(40, '-') << "lg[]" << string(40, '-') << endl;
  // rep(i, rmqN+1) { cout << lg[i] << " "; } cout << endl;

  vector<vi> rmq(lg[rmqN]+1, vi(rmqN));
  rep(i, rmqN) {
    rmq[0][i] = i;
  }

  for(int l = 1; l <= lg[rmqN]; l++) {
    for(int i = 0; i + (1 << l) - 1 < rmqN; i++) {
      int rmq_left = rmq[l-1][i];
      int rmq_right = rmq[l-1][i + (1<<(l-1))];

      if (Lvl[rmq_left] <= Lvl[rmq_right]) {
        rmq[l][i] = rmq_left;
      } else {
        rmq[l][i] = rmq_right;
      }
    }
  }
  // for(int l = 0; l <= lg[rmqN]; l++) {
  //   cout << string(40, '-') << "l:\t" << l << string(40, '-') << endl;
  //   rep(i, N) {
  //     cout << rmq[l][i] << " ";
  //   }
  //   cout << endl;
  //   rep(i, N) {
  //     cout << Lvl[rmq[l][i]] << " ";
  //   }
  //   cout << endl;
  // }

  // read and execute the queries
  rep(i, M) {
    fin >> a >> b;
    // cout << string(40, '-') << "case:\t" << i << string(40, '-') << endl;
    // cout << a << " " << b << endl;
    --a, --b;
    int x = H[a];
    int y = H[b];
    // cout << x << " " << y << endl;

    if (x > y) { swap(x, y); }

    int l = lg[y-x+1];
    int rmq_left = rmq[l][x];
    int rmq_right = rmq[l][y-(1<<l)+1];
    // cout << rmq_left << " " << rmq_right << endl;
    // cout << Lvl[rmq_left] << " " << Lvl[rmq_right] << endl;

    int lca_pos = -1;
    if (Lvl[rmq_left] <= Lvl[rmq_right]) {
      lca_pos = rmq_left;
    } else {
      lca_pos = rmq_right;
    }

    fout << Epath[lca_pos] + 1 << '\n';
  }

  return 0;
}