Cod sursa(job #1487074)

Utilizator salam1Florin Salam salam1 Data 16 septembrie 2015 02:56:46
Problema Lowest Common Ancestor Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 2.45 kb
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;

class tree {
private:
  vector<vector<int>>& G;
  int n, root;

  vector<bool> mark;
  vector<int> startPost, lvl, eulerPath, lg;
  int currIdx;
  vector<vector<int>> minInterval;

public:
  tree(int _n, int _root, vector<vector<int>>& _G):
    G(_G), 
    n(_n), 
    root(_root) { }

  void prepareLca();

  int findLca(int, int);

private:
  void prepareEuler();

  void dfs(int);

  inline int minLevel(int, int);

  void prepareRmq();
};

void tree:: prepareLca() {
  mark.assign(n + 1, false);
  startPost.resize(n + 1);
  lvl.assign(n + 1, 0);
  eulerPath.resize(2 * n + 1);

  prepareEuler();

  prepareRmq();
}

void tree:: prepareEuler() {
  currIdx = 0;
  dfs(root);
}

void tree:: dfs(int node) {
  mark[node] = true;
  startPost[node] = ++currIdx;
  eulerPath[currIdx] = node;

  for (auto x: G[node])
    if (!mark[x]) {
      lvl[x] = lvl[node] + 1;
      dfs(x);
      eulerPath[++currIdx] = node;
    }

  eulerPath[currIdx] = node;
}

inline int tree:: minLevel(int node1, int node2) {
  return lvl[node1] < lvl[node2] ? node1 : node2;
}

void tree:: prepareRmq() {
  lg.assign(currIdx + 1, 0);
  for (int i = 2; i <= currIdx; i++)
    lg[i] = lg[i >> 1] + 1;

  int step;
  for (step = 1; (1 << step) <= currIdx; step++);
  minInterval.resize(step);
  for (int i = 0; i < step; i++)
    minInterval[i].resize(currIdx + 1);

  for (int i = 1; i <= currIdx; i++)
    minInterval[0][i] = eulerPath[i];

  for (int j = 1; j < step; j++) {
    for (int i = 1; i <= currIdx - (1 << j) + 1; i++) {
      minInterval[j][i] = minLevel(
        minInterval[j - 1][i],
        minInterval[j - 1][i + (1 << (j - 1))]);
    }
  }
}

int tree:: findLca(int node1, int node2) {
  if (startPost[node1] > startPost[node2]) {
    swap(node1, node2);
  }

  int step = lg[startPost[node2] - startPost[node1] + 1];
  return minLevel(
    minInterval[step][startPost[node1]],
    minInterval[step][startPost[node2] - (1 << step) + 1]);
}

int n, q;
vector<vector<int>> G;
tree* T;

void read() {
  scanf("%d%d", &n, &q);
  G.resize(n + 1);
  int x;
  for (int i = 2; i <= n; i++) {
    scanf("%d", &x);
    G[x].push_back(i);
    G[i].push_back(x);
  }

  T = new tree(n, 1, G);
}

void solve() {
  T -> prepareLca();
  int x, y;
  while (q--) {
    scanf("%d%d", &x, &y);
    printf("%d\n", T -> findLca(x, y));
  }
}

int main() {
  freopen("lca.in", "r", stdin);
  freopen("lca.out", "w", stdout);

  read();
  solve();
  return 0;
}