Cod sursa(job #2501556)

Utilizator preda.andreiPreda Andrei preda.andrei Data 29 noiembrie 2019 21:00:19
Problema Lowest Common Ancestor Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.75 kb
#include <fstream>
#include <vector>

template <typename T>
class RmqVector {
public:
    explicit RmqVector() : RmqVector(0) {}

    explicit RmqVector(int size) {
        mins_.resize(size, {T()});
        logs_.resize(size + 1, 0);

        for (int i = 2; i <= size; i += 1) {
            logs_[i] = logs_[i / 2] + 1;
        }
    }

    void set(int pos, const T &value) {
        mins_[pos][0] = value;
    }

    T get(int left, int right) const {
        int len = right - left + 1;
        int log = logs_[len];
        int mid = left + (1 << log) - 1;

        return std::min(mins_[mid][log], mins_[right][log]);
    }

    void preprocess() {
        for (size_t i = 1; i < mins_.size(); i += 1) {
            for (int log = 0; log < logs_[i + 1]; log += 1) {
                auto mid = i - (1 << log);
                auto min_left = mins_[mid][log];
                auto min_right = mins_[i][log];

                auto new_min = std::min(min_left, min_right);
                mins_[i].push_back(new_min);
            }
        }
    }

private:
    std::vector<std::vector<T>> mins_;
    std::vector<int> logs_;
};

class EulerData
{
public:
    explicit EulerData(int nodes) {
        node_by_order_.resize(nodes, -1);
        order_by_node_.resize(nodes, -1);
        pos_in_tour_.resize(nodes, -1);

        int tour_size = 2 * (nodes - 1) + 1;
        tour_ = RmqVector<int>(tour_size);

        next_order_ = 0;
        tour_pos_ = 0;
    }

    void solveRmq() {
        tour_.preprocess();
    }

    int lca(int a, int b) const {
        int pos_a = pos_in_tour_[a];
        int pos_b = pos_in_tour_[b];

        int left = std::min(pos_a, pos_b);
        int right = std::max(pos_a, pos_b);

        int order_lca = tour_.get(left, right);
        return node_by_order_[order_lca];
    }

    void addNode(int node) {
        if (pos_in_tour_[node] == -1) {
            int order = next_order_;
            next_order_ += 1;

            order_by_node_[node] = order;
            node_by_order_[order] = node;
            pos_in_tour_[node] = tour_pos_;
        }

        tour_.set(tour_pos_, order_by_node_[node]);
        tour_pos_ += 1;
    }

private:
    std::vector<int> node_by_order_;
    std::vector<int> order_by_node_;
    std::vector<int> pos_in_tour_;

    RmqVector<int> tour_;
    int next_order_;
    int tour_pos_;
};

using Tree = std::vector<std::vector<int>>;

void eulerTour(const Tree &tree, int node, int father, EulerData &euler)
{
    euler.addNode(node);

    for (const auto &son : tree[node]) {
        if (son != father) {
            eulerTour(tree, son, node, euler);
            euler.addNode(node);
        }
    }
}

EulerData eulerTour(const Tree &tree) {
    int nodes = tree.size();
    EulerData euler(nodes);

    eulerTour(tree, 0, -1, euler);
    euler.solveRmq();

    return euler;
}

std::vector<int> lca(const Tree &tree,
                     const std::vector<std::pair<int, int>> &queries) {
    auto euler = eulerTour(tree);

    std::vector<int> answers;
    for (const auto &q : queries) {
        int a = q.first;
        int b = q.second;
        answers.push_back(euler.lca(a, b));
    }
    return answers;
}

int main()
{
    std::ifstream fin("lca.in");
    std::ofstream fout("lca.out");

    int nodes, tests;
    fin >> nodes >> tests;

    std::vector<std::vector<int>> tree(nodes);
    for (int i = 1; i < nodes; i += 1) {
        int father;
        fin >> father;
        tree[father - 1].push_back(i);
        tree[i].push_back(father - 1);
    }

    std::vector<std::pair<int, int>> queries(tests);
    for (auto &q : queries) {
        fin >> q.first >> q.second;
        q.first -= 1;
        q.second -= 1;
    }

    auto res = lca(tree, queries);
    for (const auto &node : res) {
        fout << node + 1 << "\n";
    }

    return 0;
}