Cod sursa(job #3305113)

Utilizator jumaracosminJumara Cosmin-Mihai jumaracosmin Data 30 iulie 2025 02:18:41
Problema Lowest Common Ancestor Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 2.76 kb
#include <bits/stdc++.h>
    
std::ifstream fin("lca.in");
std::ofstream fout("lca.out");

//#define fin std::cin
//#define fout std::cout

/*
    LCA - Euler tour + RMQ
    --------------
    
    Gasim forma Euler a arborelui si momentul in care intra fiecare nod in parcurgere
    si adancimea fiecaruia.

    Precalculam pe adancimile din parcurgere minimul cu RMQ.

    OBS: LCA-ul unor doua noduri X si Y o sa se afle intre momentele de intrare.
    LCA-ul o sa aiba depth-ul minim gasit in parcurgerea euler intre cele doua momente

    OBS: Pentru paduri cream o radcina fictiva -1.
*/

const int nmax = 1e5 + 5;
const int logmax = 20;

int n, q;
std::vector<int> graph[nmax];
int father[nmax];

int enter[nmax];            // enter[i] = cand apare prima data nodul i in parcurgerea euler
std::vector<int> euler;     // parcurgerea euler
std::vector<int> depth;     // depth-ul nodului euler[i] din parcurgerea euler

int rmq[logmax][2 * nmax];      // facem rmq pentru nod cu depth minim
int logarithm[2 * nmax];

void dfs(int node, int parent, int level)
{
    enter[node] = euler.size();
    euler.push_back(node);
    depth.push_back(level);

    for(auto adj : graph[node])
        if(adj != parent)
        {
            dfs(adj, node, level + 1);
            euler.push_back(node);     // ne intoarcem in node
            depth.push_back(level);
        }
}

void buildRMQ()
{
    logarithm[0] = logarithm[1] = 0;
    for(int i = 2; i <= depth.size(); ++i)
        logarithm[i] = logarithm[i / 2] + 1;

    // doresc sa pastrez indici ca sa pot obtine nodul din parcurgere
    for(int i = 0; i < depth.size(); ++i)
        rmq[0][i] = i;

    for(int i = 1; i <= logarithm[depth.size()]; ++i)
        for(int j = 0; j <= depth.size() - (1 << i); ++j)
        {
            int first = rmq[i - 1][j];
            int second = rmq[i - 1][j + (1 << (i - 1))];
            rmq[i][j] = (depth[first] < depth[second] ? first : second);
        }
}

int lca(int x, int y)
{
    int left = enter[x];
    int right = enter[y];

    if(left > right)
        std::swap(left, right);

    int len = logarithm[right - left + 1];

    int ans1 = rmq[len][left];              // gasesc indicele cu depth minim
    int ans2 = rmq[len][right - (1 << len) + 1];

    return (depth[ans1] < depth[ans2] ? euler[ans1] : euler[ans2]);
}

int main()
{
    
    fin >> n >> q;
    for(int i = 2; i <= n; ++i)
    {
        fin >> father[i];
        graph[i].push_back(father[i]);
        graph[father[i]].push_back(i);
    }

    int root = 1;
    father[root] = 0;
    dfs(root, 0, 0);

    buildRMQ();

    while(q--)
    {
        int x, y;
        fin >> x >> y;
        fout << lca(x, y) << "\n";
    }

    return 0;
}