Cod sursa(job #2969208)

Utilizator cberindeCodrin Berinde cberinde Data 22 ianuarie 2023 18:48:46
Problema Lowest Common Ancestor Scor 10
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 2.75 kb
//este problema lca de pe infoarena

//prezentam aici o metoda care foloseste linearizarea a treia a arborelui
//care consta in parcurgerea arborelui si notarea in lista linearizata a
//fiecarui nod de fiecare data cand trecem prin el
//pentru dou noduri u, v, lca-ul lor este nodul cu cea mai mica adancime intre
//prima aparitie a lui u si prima aparitie a lui v in forma linearizata

#include <bits/stdc++.h>
using namespace std;
ifstream fin("lca.in");
ofstream fout("lca.out");

int n, t;
vector<int> adi[100001];
int dpth[100001];
int apa[100001]; // prima aparitie a fiecarui nod
int linea[200001], lng;
vector<int> spta[200001]; // sparse table

void citire() {
    fin >> n >> t;
    int a;
    for(int i = 2; i <= n; i++) {
        fin >> a;
        adi[a].push_back(i);
    }
}

void calc_dpth(int nod, int d) {
    dpth[nod] = d;
    for(auto nou : adi[nod]) {
        calc_dpth(nou, d + 1);
    }
}

void linea3(int nod) {
    linea[++lng] = nod;
    apa[nod] = lng;
    for(auto nou : adi[nod]) {
        linea3(nou);
        linea[++lng] = nod;
    }
}

int compa(int nod1, int nod2) {
    if(dpth[nod1] < dpth[nod2])
        return nod1;
    return nod2;
}

int main() {
    citire();
    calc_dpth(1, 0);
    //facem linearizarea a treia a arborelui
    linea3(1);
    // for(int i = 1; i <= lng; i++) {
    //     cout << linea[i] << " ";
    // }
    // cout << endl;
    
    //incepem sa precalculam sparse table (spta)
    for(int i = 1; i <= lng; i++) {
        spta[i].push_back(linea[i]);
    }

    //parcurgem toate puterile lui 2 pana la cea mai mare cat incape
    for(int putere = 0; putere <= 17; putere++) {
        for(int i = 1; i <= lng; i++) {
            if(spta[i].size() == putere + 1 && (i + (1 << putere) <= lng) && spta[i + (1 << putere)].size() == putere + 1) {
                spta[i].push_back(compa(spta[i][putere], spta[i + (1 << putere)][putere]));
            }
        }
    }
    // for(int i = 1; i <= lng; i++) {
    //     cout << i << ": ";
    //     for(auto it : spta[i]) {
    //         cout << it << " ";
    //     }
    //     cout << "\n";
    // }

    //procesam query-urile
    int u, v, dife;
    for(int i = 1; i <= t; i++) {
        fin >> u >> v;
        if(apa[u] > apa[v])
            swap(u, v);
        dife = apa[v] - apa[u];

        //cazul in care coincid
        if(dife == 0) {
            fout << u << "\n";
            continue;
        }

        //calculam cea mai mare putere a lui 2 mai mica sau egala cu dife
        int pt = 17;
        while((1 << pt) > dife) {
            pt--;
        }
        //raspundem la query
        fout << compa(spta[apa[u]][pt], spta[apa[v] - dife][pt]) << "\n";
    }


    return 0;
}