Cod sursa(job #3235296)

Utilizator anacerneaana cernea anacernea Data 16 iunie 2024 20:21:16
Problema Lowest Common Ancestor Scor 30
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 2.9 kb
//Se dă un arbore cu rădăcină T. Cel mai apropiat strămoş comun a două noduri u şi v este nodul w care este
// strămoş al ambelor noduri u şi v şi are cea mai mare adâncime în T.
//
//Considerăm că arborele T are n noduri şi are rădăcina în nodul 1. Dându-se o mulţime arbitrară P = {{u,v}},
// cu m perechi neordonate de noduri din T, se cere să se determine cel mai apropiat strămoş al fiecărei perechi din P.
//
//

#include<fstream>
#include<iostream>
#include<vector>
#include<cmath>
using namespace std;

const int nmax = 100001;
const int lmax = 20;

int k, n, m;
int nivel[nmax << 1], euler[nmax << 1],prima_apar[nmax];
int rmq[nmax][lmax];
vector<int> g[nmax];
ifstream fin("lca.in");
ofstream fout("lca.out");

void parcurgere(int nod, int niv_curent) //trece prin arbore si creeaza reprezentarea euler
{
    k++;
    euler[k] = nod;
    nivel[k] = niv_curent ;
    prima_apar[nod] = k;

    for (auto it: g[nod])
    {
        parcurgere(it, niv_curent +1);
        k++;
        euler[k] = nod;
        nivel[k] = niv_curent ;

    }
}
void preprocesare(int n)
{
    for(int i = 0; i < n; i++)
        rmq[i][0] = nivel[i];
    for(int j = 1; (1 << j) <= n; j++)
        for(int i = 0; i + (1 << j) - 1 < n; i++)
            rmq[i][j] = min(rmq[i][j - 1], rmq[i + (1 << (j - 1))][j - 1]);
}
void preprocesare1(int n) {
    for (int i = 0; i <= k; i++)
        rmq[i][0] = i;
    for (int j = 1; (1 << j) <= k + 1; j++)
        for (int i = 0; i + (1 << j) - 1 <= k; i++) {
            if (nivel[rmq[i][j - 1]] < nivel[rmq[i + (1 << (j - 1))][j - 1]])
                rmq[i][j] = rmq[i][j - 1];
            else
                rmq[i][j] = rmq[i + (1 << (j - 1))][j - 1];
        }
}
int query(int nod1, int nod2)
{
    int x = prima_apar[nod1], y = prima_apar[nod2];
    int k = log2(y - x + 1);
    if (rmq[x][k] < rmq[y - (1 << k) + 1][k])
        return euler[x];
    else
        return euler[y - (1 << k) + 1]; //ceva aici nu da bine
    //return min(rmq[x][k], rmq[y - (1 << k) + 1][k]); //trb sa punem poz
}
int query1(int nod1, int nod2) {
    int x = prima_apar[nod1], y = prima_apar[nod2];
    if (x > y) swap(x, y);
    int length = y - x + 1;
    int k = log2(length);
    if (nivel[rmq[x][k]] < nivel[rmq[y - (1 << k) + 1][k]])
        return euler[rmq[x][k]];
    else
        return euler[rmq[y - (1 << k) + 1][k]];
}

int main()
{
    int x, a, b;
    fin >> n >> m;
    //1 1 2 2 2 4 4 6 3 3
    for (int i = 2; i <= n; i++) {
        fin >> x;
        g[x].push_back(i); //se pun copiii
    }
    k = -1;
    parcurgere(1, 0);
    /*for (int i = 0; i <= k; i++)
        cout<<euler[i]<<" ";
    cout<<"\n";
    for (int i = 0; i <= k; i++)
        cout<<nivel[i]<<" ";
    cout<<"\n";*/

    preprocesare1(k);

    for(int i=0;i<m;i++){
        fin>>a>>b;
        fout<<query1(a,b)<<endl;
    }
    return 0;
}