Cod sursa(job #2990557)

Utilizator AleXutzZuDavid Alex Robert AleXutzZu Data 8 martie 2023 09:32:25
Problema Lowest Common Ancestor Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 2.28 kb
#include <iostream>
#include <fstream>
#include <vector>

std::vector<int> euler(1, 0);
std::vector<int> depth;
std::vector<int> euler_depth(1, 0);
std::vector<std::vector<int>> tree;
std::vector<int> pos;
std::vector<int> rmq;

void dfs(int start) {
    for (const auto &x: tree[start]) {
        euler.push_back(start);
        depth[x] = depth[start] + 1;
        euler_depth.push_back(depth[start]);
        dfs(x);
    }
    euler.push_back(start);
    euler_depth.push_back(depth[start]);
}

int main() {
    std::ifstream input("lca.in");
    std::ofstream output("lca.out");

    int n, m;
    input >> n >> m;
    tree.resize(n + 1);
    depth.resize(n + 1, 0);
    pos.resize(n + 1, INT32_MAX);

    for (int i = 2; i <= n; ++i) {
        int x;
        input >> x;
        tree[x].push_back(i);
    }

    dfs(1);

    size_t s = euler.size();
    for (size_t i = 0; i < s; ++i) {
        pos[euler[i]] = std::min<int>(pos[euler[i]], i);
    }

    int root = 1;
    while (root * root <= s) root++;
    root--;

    int k = 0;
    while (k * root + 1 <= s) {
        int min = INT32_MAX;
        int min_pos = 0;
        for (int i = k * root + 1; i <= std::min<int>((k + 1) * root, s - 1); ++i) {
            if (euler_depth[i] < min) {
                min = euler_depth[i];
                min_pos = i;
            }
        }
        rmq.push_back(min_pos);
        k++;
    }

    while (m--) {
        int p, q;
        input >> p >> q;

        int left = std::min(pos[p], pos[q]);
        int right = std::max(pos[p], pos[q]);

        int min = INT32_MAX;
        int min_pos = 0;
        for (int i = (left - 1) / root + 1; i < (right - 1) / root; ++i) {
            if (euler_depth[rmq[i]] < min) {
                min = euler_depth[rmq[i]];
                min_pos = rmq[i];
            }
        }

        for (int i = std::max((right - 1) / root * root, left); i <= right; ++i) {
            if (euler_depth[i] < min) {
                min = euler_depth[i];
                min_pos = i;
            }
        }

        for (int i = left; i < std::min(((left - 1) / root + 1) * root + 1, right + 1); ++i) {
            if (euler_depth[i] < min) {
                min = euler_depth[i];
                min_pos = i;
            }
        }

        output << euler[min_pos] << '\n';
    }

    return 0;
}