Cod sursa(job #2501491)

Utilizator preda.andreiPreda Andrei preda.andrei Data 29 noiembrie 2019 19:56:16
Problema Lowest Common Ancestor Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.81 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) {
        nodes_by_index_.resize(nodes, -1);
        indexes_by_node_.resize(nodes, -1);
        first_appearance_.resize(nodes, -1);

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

        nodes_used_ = 0;
        tour_index_ = 0;
    }

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

    int lca(int a, int b) const {
        int tour_pos_a = first_appearance_[a];
        int tour_pos_b = first_appearance_[b];

        int left = std::min(tour_pos_a, tour_pos_b);
        int right = std::max(tour_pos_a, tour_pos_b);

        int index_lca = rmq_.get(left, right);
        return nodes_by_index_[index_lca];
    }

    void addNode(int node) {
        if (first_appearance_[node] == -1) {
            indexes_by_node_[node] = nodes_used_;
            nodes_by_index_[nodes_used_] = node;
            first_appearance_[node] = tour_index_;
            nodes_used_ += 1;
        }
        rmq_.set(tour_index_, indexes_by_node_[node]);
        tour_index_ += 1;
    }

private:
    std::vector<int> nodes_by_index_;
    std::vector<int> indexes_by_node_;
    std::vector<int> first_appearance_;
    RmqVector<int> rmq_;
    int nodes_used_;
    int tour_index_;
};

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) {
            continue;
        }

        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;
}