Cod sursa(job #2071767)

Utilizator mlc_oficialBoris Barca mlc_oficial Data 20 noiembrie 2017 23:13:58
Problema Lowest Common Ancestor Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 5.83 kb
#include <fstream>
#include <iostream>
#include <vector>
#include <cassert>

using namespace std;

struct EmptyType {};

// Remember to Init() after adding the edges
template<typename EdgeAttributes = EmptyType>
class Graph {
  private:
    Graph();
    struct Edge : private EdgeAttributes {
        int from, to;
        Edge() { }
        Edge(const int _from, const 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;
    };
  public:
    explicit Graph(const int N, const 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 Init() {
        ReorderEdges();
    }
    
    size_t size() const {
        return (size_t)n_;
    }

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

  protected:
    void ReorderEdges() {
        edges_.resize(in_.size());
        for (auto&& e : in_) { offset_[e.from] += 1; }
        for (int i = 1; i <= n_; i += 1) { 
            offset_[i] += offset_[i - 1]; 
        }
        for (auto&& e : in_) { 
            edges_[--offset_[e.from]] = e.to; 
        }
        in_.clear();    
    }
    
    int n_;
    vector<int> offset_, edges_;
    vector<Edge> in_;
};

template<typename EdgeAttributes = EmptyType>
class Tree : public Graph<EdgeAttributes> {
  private:
    Tree() { }
  public:
    explicit Tree(int N) : Graph<EdgeAttributes>(N, N - 1) { }
    
    virtual void Init(const int root=0) {
        this->ReorderEdges();
        Dfs(root);
    }
    
    int parent(const int node) const {
        return parent_[node];
    }
    
    int preorder(const int idx) const {
        return preorder_[idx];
    }
  private:
    void Dfs(const int root) {
        parent_.assign(this->n_, -1);
        
        vector<int> stk;
        stk.push_back(root);
        while (not stk.empty()) {
            const int node = stk.back();
            stk.pop_back();
            
            preorder_.push_back(node);
            
            for (auto&& son : (*this)[node]) {
                if (parent_[son] == -1) {
                    parent_[son] = node;
                    stk.push_back(son);
                }
            }
        }
    }
    vector<int> parent_, preorder_;
};

class SchieberVishkinLCA {
  private:
    SchieberVishkinLCA();

    static inline int lsb(int value) {
        return value & -value;
    }
    
    static inline int msb(int v) {
        v |= v >> 1;
        v |= v >> 2;
		v |= v >> 4;
		v |= v >> 8;
		v |= v >> 16;
		return v >> 1;
    }
  public:
    template<typename EdgeAttributes>
    explicit SchieberVishkinLCA(Tree<EdgeAttributes>& G, int root = 0) : idx_(G.size()), max_idx_(G.size()), ancestor_height_(G.size()), path_parent_(G.size()) {
        const int n = G.size();
        
        for (int i = 0; i < n; i += 1) {
            idx_[G.preorder(i)] = i + 1;    
        }
        max_idx_ = idx_;
        for (int i = n - 1; i > 0; i -= 1) {
            const int node = G.preorder(i);
            if (lsb(max_idx_[G.parent(node)]) < lsb(max_idx_[node])) {
                max_idx_[G.parent(node)] = max_idx_[node];
            }
        }
        
        ancestor_height_[root] = 0;
        for (int i = 1; i < n; i += 1) {
            const int node = G.preorder(i);
            ancestor_height_[node] = ancestor_height_[G.parent(node)] | lsb(max_idx_[node]);
        }
        
        path_parent_[idx_[root] - 1] = root;
        for (int i = 0; i < n; i += 1) {
            const int node = G.preorder(i);
            for (auto&& son : G[node]) {
                if (G.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:
    vector<int> idx_, max_idx_, ancestor_height_, path_parent_;
};

int main() {
    #ifdef INFOARENA
    ifstream cin("lca.in");
    ofstream cout("lca.out");
    #endif
    
    int n, q; cin >> n >> q;
    Tree<> tree(n);
    for (int i = 1; i < n; i += 1) {
        int parent; cin >> parent;
        tree.AddEdge(parent - 1, i);
    }
        
    tree.Init();
    SchieberVishkinLCA lca_solver(tree);
    while (q--) {
        int x, y; cin >> x >> y; x -= 1; y -= 1;
        cout << 1+lca_solver.Query(x, y) << '\n';
    }
}