Cod sursa(job #2054379)

Utilizator mlc_oficialBoris Barca mlc_oficial Data 1 noiembrie 2017 22:08:24
Problema Lowest Common Ancestor Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 7.48 kb
#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include <iostream>
#include <vector>
#include <fstream>
#include <memory>

using namespace std;

class Reader {
public:
    Reader(istream& _in) : in(_in), idx(kBuffSize - 1), buff(new char[kBuffSize]) { Advance(); }
    
    template<typename T>
    Reader& operator>>(T& value) {
        while (not isdigit(Current())) {
            Advance();
        }
        
        value = 0;
        while (isdigit(Current())) {
            value = (value << 1) + (value << 3) + (Current() - '0');
            Advance();
        }
        return *this;
    }
private:
    static constexpr int kBuffSize = 1 << 12;
    
    char Current() const {
        return buff[idx];
    }
    
    void Advance() {
        if (++idx == kBuffSize) {
            in.read(buff.get(), kBuffSize);
            idx = 0;
        }
    }
    
    istream& in;
    int idx;
    unique_ptr<char[]> buff;
};

class Printer {
public:
    Printer(ostream& _out) : out(_out), idx(0), buff(new char[kBuffSize]) { }
    ~Printer() { Flush(); out.flush(); }

    Printer& operator<<(int value) {
        char digits[10];
        int num_digits = 0;
        do {
            const int aux = ((uint64_t)3435973837U * value) >> 35;
            digits[num_digits++] = value - (aux << 1) - (aux << 3) + '0';
            value = aux;
        } while (value > 0);
        
        while (num_digits--) {
            PutChar(digits[num_digits]);
        }
        return *this;
    }
    
    Printer& operator<<(const char& ch) {
        PutChar(ch);
        return *this;
    }
private:
    static constexpr int kBuffSize = 1 << 12;
    
    void Flush() {
        out.write(buff.get(), idx);    
    }
    
    void PutChar(const char& ch) {
        buff[idx++] = ch;
        if (idx == kBuffSize) {
            Flush();
            idx = 0;
        }
    }
    
    ostream& out;
    int idx;
    unique_ptr<char[]> buff;    
};

class Graph {
private:
    struct Edge {
        int from, to;
        Edge() { }
        Edge(const int _from, const int _to) : 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:
    Range<int> operator [](int u) { 
        return Range<int>(&edges[offset[u]], &edges[offset[u + 1]]); 
    }
     
    Graph() = default;
    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) { in.emplace_back(x, y); }
     
    void Init() {
        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();
    }
     
    size_t size() const {
        return (size_t)n;
    }
private:    
    int n;
    vector<int> offset, edges;
    vector<Edge> in;
};
 
class SchieberVishkinLCA {
private:
    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:
    SchieberVishkinLCA() = default;
    SchieberVishkinLCA(Graph& G, int root) : idx(G.size()), max_idx(G.size()), ancestor_height(G.size()), path_parent(G.size()) {
        int n = G.size();
        vector<int> parent(n), vertices(n);
         
        auto Dfs = [&]() {
            int stack_size = 1, euler_idx = 1;
            vertices[0] = root;
            parent[root] = -1;
            while (stack_size > 0) {
                const int node = vertices[--stack_size];
                idx[node] = euler_idx++;
                for (auto&& son : G[node]) {
                    if (parent[node] != son) {
                        parent[son] = node;
                        vertices[stack_size++] = son;
                    }
                }
            }
        };
         
        auto Bfs = [&]() {
            int q_front = 0, q_end = 1;
            vertices[0] = root;
            parent[root] = -1;
            while (q_front != q_end) {
                const int node = vertices[q_front++];
                for (auto&& son : G[node]) {
                    if (parent[node] != son) {
                        parent[son] = node;
                        vertices[q_end++] = son;
                    }
                }
            }
        };
         
        Dfs(); Bfs();
        max_idx = idx;
        for (int i = n - 1; i > 0; i -= 1) {
            const int node = vertices[i];
            if (lsb(max_idx[parent[node]]) < lsb(max_idx[node])) {
                max_idx[parent[node]] = max_idx[node];
            }
        }
         
        ancestor_height[root] = 0;
        for (int i = 1; i < n; i += 1) {
            const int node = vertices[i];
            ancestor_height[node] = ancestor_height[parent[node]] | lsb(max_idx[node]);
        }
         
        path_parent[idx[root] - 1] = root;
        for (int i = 0; i < n; i += 1) {
            const int node = vertices[i];
            for (auto&& son : G[node]) {
                if (parent[node] == son) {
                    continue;
                }
                 
                path_parent[idx[son] - 1] = (max_idx[node] == max_idx[son]) ? path_parent[idx[node] - 1] : node;
            }
        }
    }
     
    int Query(int x, int y) const {
        const int Ix = max_idx[x], Iy = max_idx[y];
        const int hIx = lsb(Ix), hIy = lsb(Iy);
        const int msb_mask = msb((Ix ^ Iy) | hIx | hIy);
        const int mask = lsb(ancestor_height[x] & ancestor_height[y] & ~msb_mask);
         
        int left, right;
         
        if (mask == hIx) {
            left = x;
        } else {
            const int kMask = msb(ancestor_height[x] & (mask - 1));
            left = path_parent[((idx[x] & ~kMask) | (kMask + 1)) - 1];
        }
         
        if (mask == hIy) {
            right = y;
        } else {
            const int kMask = msb(ancestor_height[y] & (mask - 1));
            right = path_parent[((idx[y] & ~kMask) | (kMask + 1)) - 1];
        }
        return (idx[left] < idx[right]) ? left : right;
    }
private:
    vector<int> idx, max_idx, ancestor_height, path_parent;
};
 
int main() {
    #ifdef INFOARENA
    ifstream cin("lca.in");
    ofstream cout("lca.out");
    #endif
    cin.tie(0);
    ios_base::sync_with_stdio(false);
    
    Reader r(cin);
    Printer p(cout);
    int n, m; r >> n >> m;
    Graph G(n, n - 1);
    for (int i = 1; i < n; i += 1) {
        int parent; r >> parent; parent -= 1;
        G.AddEdge(parent, i);
    }
    G.Init();
     
    SchieberVishkinLCA LcaSolver(G, 0);
    for (int i = 0; i < m; i += 1) {
        int x, y; r >> x >> y; x -= 1; y -= 1;
        p << 1 + LcaSolver.Query(x, y) << '\n';
    }
}