Cod sursa(job #2037996)

Utilizator danny794Dan Danaila danny794 Data 13 octombrie 2017 08:05:00
Problema Lowest Common Ancestor Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 2.31 kb
#include <cmath>
#include <fstream>
#include <utility>
#include <vector>

std::ifstream r("lca.in");
std::ofstream w("lca.out");

class RMQ {
 public:
  RMQ(const std::vector<int>& levels) : levels_(levels) {}

  void build() {
    size_t size = levels_.size();
    matrix_.resize(size);
    size_t pos = 0;
    for (size_t i = 0; i < size; i++) {
      matrix_[i].resize(1 + (int) (std::log(size) / std::log(2)));
      matrix_[i][0] = i;
    }
    for (size_t d = 1; d < matrix_.front().size(); d++) {
      for (size_t i = 0; i < size; i++) {
        matrix_[i][d] = matrix_[i][d - 1];
        pos = i + (1 << (d - 1));
        if (pos < size) {
          if (levels_[matrix_[i][d]] > levels_[matrix_[pos][d - 1]]) {
            matrix_[i][d] = matrix_[pos][d - 1];
          }
        }
      }
    }
  }

  int query(int a, int b) {
    if (a > b) {
      std::swap(a, b);
    }
    int d = (int) (std::log(b - a + 1) / std::log(2));
    int pos = b - (1 << d) + 1;
    if (levels_[matrix_[a][d]] < levels_[matrix_[pos][d]]) {
      return matrix_[a][d];
    } else {
      return matrix_[pos][d];
    }
  }

 private:
  const std::vector<int>& levels_;
  std::vector<std::vector<int>> matrix_;
};

class LCA {
 public:
  LCA(int n)
    : length(0),
      euler(2 * n - 1),
      levels(2 * n - 1),
      index(n + 1),
      rmq(levels) {}

  void read() {
    std::vector<std::vector<int>> children;
    children.resize(index.size());
    int parent;
    for (size_t i = 2; i < index.size(); i++) {
      r >> parent;
      children[parent].emplace_back(i);
    }
    eulerTraverse(1, 0, children);
    rmq.build();
  }

  int query(int a, int b) {
    return euler[rmq.query(index[a], index[b])];
  }

 private:
  void eulerTraverse(
      int idx, int lvl, const std::vector<std::vector<int>>& children) {
    for (const auto& child : children[idx]) {
      save(idx, lvl);
      eulerTraverse(child, lvl + 1, children);
    }
    save(idx, lvl);
  }

  void save(int idx, int lvl) {
    index[idx] = length;
    euler[length] = idx;
    levels[length] = lvl;
    length++;
  }

  int length;
  std::vector<int> euler;
  std::vector<int> levels;
  std::vector<int> index;
  RMQ rmq;
};

int main() {
  int n, tests, a, b;
  r >> n >> tests;
  LCA tree(n);
  tree.read();
  while (tests--) {
    r >> a >> b;
    w << tree.query(a, b) << "\n";
  }
  return 0;
}