Cod sursa(job #2210194)

Utilizator mlc_oficialBoris Barca mlc_oficial Data 5 iunie 2018 21:06:16
Problema Lowest Common Ancestor Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 6.05 kb
#include <vector>
#include <cstdio>

namespace algo {

struct EmptyType {};

// Remember to Init() after adding the edges
template <typename EdgeAttributes = EmptyType>
class Graph {
 private:
  template <typename T> struct Range;

 public:
  explicit Graph(int n, int m = 0) : n_(n), offset_(n + 1) {
    if (m > 0) {
      in_.reserve(m);
    }
  }

  void AddEdge(int x, int y, const EdgeAttributes attr = EdgeAttributes()) {
    in_.emplace_back(x, y, attr);
  }

  virtual void AdditionalInit() {}

  void Init() {
    ReorderEdges();
    AdditionalInit();
  }

  size_t size() const {
    return (size_t)n_;
  }

  Range<int> operator[](const int u) {
    return Range<int>(&edges_[offset_[u]], &edges_[offset_[u + 1]]);
  }

  int node(const int edge_idx) const {
    return in_[edge_idx].to;
  }

  EdgeAttributes value(const int edge_idx) const {
    return in_[edge_idx];
  }

 private:
  Graph() = delete;

  struct Edge : public EdgeAttributes {
    int from, to;
    Edge() {}
    Edge(int from_, int to_, const EdgeAttributes& attr)
        : EdgeAttributes(attr), from(from_), to(to_) {}
  };

  template <typename T>
  struct Range {
    struct Iterator {
      T& operator*() const                        { return *iter; }
      bool operator!=(const Iterator& rhs) const  { return iter != rhs.iter; }
      void operator++()                           { ++iter; }
      T* operator+(int i) const                   { return iter + i; }
      size_t operator-(const Iterator& rhs) const { return iter - rhs.iter; }
      T* iter;
    };

    Range(T* _first, T* _last) : first({_first}), last({_last}) {}
    T operator[](const int i) { return *(first + i); }
    size_t size() const       { return last - first; }
    Iterator& begin()         { return first; }
    Iterator& end()           { return last; }
    Iterator first, last;
  };

  void ReorderEdges() {
    edges_.resize(in_.size());
    for (auto&& e : in_) {
      ++offset_[e.from];
    }
    for (int i = 1; i <= n_; ++i) {
      offset_[i] += offset_[i - 1];
    }
    for (size_t i = 0; i < in_.size(); ++i) {
      edges_[--offset_[in_[i].from]] = i;
    }
  }

  int n_;
  std::vector<int> offset_, edges_;
  std::vector<Edge> in_;
};

}  // namespace algo

namespace algo {

template <typename EdgeAttributes=EmptyType>
class Tree : public Graph<EdgeAttributes> {
 public:
  explicit Tree(int n, int root=0) : Graph<EdgeAttributes>(n, n - 1), root_(root) {}

  void AdditionalInit() override {
    DepthSearch(root_);
  }

  int parent(int node) const {
    return parent_[node];
  }

  int preorder(int node) const {
    return order_[node];
  }

  int root() const {
    return root_;
  }

 private:
  Tree() = delete;

  void DepthSearch(int root) {
    parent_.assign(this->size(), -1);
    order_.reserve(this->size());
    std::vector<int> stk = {root};
    while (not stk.empty()) {
      int node = stk.back();
      order_.push_back(node);
      stk.pop_back();
      for (auto it : this->operator[](node)) {
        int to = this->node(it);
        if (parent_[to] == -1 and to != root) {
          parent_[to] = node;
          stk.push_back(to);
        }
      }
    }
  }

  std::vector<int> parent_, order_;
  int root_;
};

}  // namespace algo


namespace algo {

class SchieberVishkinLCA {
 public:
  template <typename EdgeAttributes>
  explicit SchieberVishkinLCA(Tree<EdgeAttributes>& tree)
      : idx_(tree.size()),
        max_idx_(tree.size()),
        ancestor_height_(tree.size()),
        path_parent_(tree.size()) {
    const int n = tree.size();

    for (int i = 0; i < n; ++i) {
      idx_[tree.preorder(i)] = i + 1;
    }
    max_idx_ = idx_;
    for (int i = n - 1; i > 0; --i) {
      const int node = tree.preorder(i);
      if (lsb(max_idx_[tree.parent(node)]) < lsb(max_idx_[node])) {
        max_idx_[tree.parent(node)] = max_idx_[node];
      }
    }

    ancestor_height_[tree.root()] = 0;
    for (int i = 1; i < n; ++i) {
      const int node = tree.preorder(i);
      ancestor_height_[node] =
          ancestor_height_[tree.parent(node)] | lsb(max_idx_[node]);
    }

    path_parent_[idx_[tree.root()] - 1] = tree.root();
    for (int i = 0; i < n; ++i) {
      const int node = tree.preorder(i);
      for (auto&& edge : tree[node]) {
        const int son = tree.node(edge);
        if (tree.parent(node) == son) {
          continue;
        }

        path_parent_[idx_[son] - 1] = (max_idx_[node] == max_idx_[son])
                                          ? path_parent_[idx_[node] - 1]
                                          : node;
      }
    }
  }

  int Query(const int x, const int y) const {
    const int ix = max_idx_[x], iy = max_idx_[y];
    const int h_ix = lsb(ix), h_iy = lsb(iy);
    const int msb_mask = msb((ix ^ iy) | h_ix | h_iy);
    const int mask = lsb(ancestor_height_[x] & ancestor_height_[y] & ~msb_mask);
    const int msb_x = msb(ancestor_height_[x] & (mask - 1));
    const int msb_y = msb(ancestor_height_[y] & (mask - 1));

    const int lhs = (mask == h_ix)
                        ? x
                        : path_parent_[((idx_[x] & ~msb_x) | (msb_x + 1)) - 1];
    const int rhs = (mask == h_iy)
                        ? y
                        : path_parent_[((idx_[y] & ~msb_y) | (msb_y + 1)) - 1];

    return (idx_[lhs] < idx_[rhs]) ? lhs : rhs;
  }

 private:
  SchieberVishkinLCA() = delete;

  static int lsb(int value) {
    return value & -value;
  }

  static int msb(int v) {
    v |= v >> 1;
    v |= v >> 2;
    v |= v >> 4;
    v |= v >> 8;
    v |= v >> 16;
    return v >> 1;
  }

  std::vector<int> idx_, max_idx_, ancestor_height_, path_parent_;
};

}  // namespace algo

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

    int n, q;
    scanf("%d%d", &n, &q);
    algo::Tree<> tree(n);
    for (int i = 1; i < n; ++i) {
        int parent;
        scanf("%d", &parent);
        tree.AddEdge(parent - 1, i);
    }

    tree.Init();

    algo::SchieberVishkinLCA lca(tree);
    while (q--> 0) {
        int u, v;
        scanf("%d%d", &u, &v);
        --u; --v;
        printf("%d\n", 1 + lca.Query(u, v));
    }

    return 0;
}