Cod sursa(job #2969164)

Utilizator cberindeCodrin Berinde cberinde Data 22 ianuarie 2023 17:18:09
Problema Lowest Common Ancestor Scor 10
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.91 kb
//este problema lowest common ancestor de pe infoarena
//arborele este dat prin vector de tati, iar 1 este mereu radacina
//vom prezenta aici metoda de a determina lca-ul folosind o lista, pentru fiecare
//nod stocand ce nod se afla mai sus de e cu 1, 2, 4, 8, ... pozitii

//mai intai, aducem nodurile u si v pentru care vrem sa determinam lca-ul
//la acelasi nivel in arbore, urmand sa aflam lca pt u' si v'.

//cautam binar in sus si cand gasim cele mai de sus noduri care nu coincid pt u si v
//aducem u si v fix in acele pozitii

//rezolvarea aceasta NU AR OBTINE PUNCTAJ MAXIM PE INFOARENA, deoarece n este prea mare...

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

int n, t;
vector<int> adi[10001];
int dpth[10001];
vector<int> ancestors[10001]; // tine minte stramosii pe pozitii puteri ale lui 2

void citire() {
    fin >> n >> t;
    int a;
    for(int i = 2; i <= n; i++) {
        fin >> a;
        adi[a].push_back(i);
        ancestors[i].push_back(a); // stramosul cu 1 mai sus (tatal) (2^(0) --> pozitia 0 in vector)
        //cout << "--" << ancestors[i][0];
    }
}

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

int main() {
    citire();
    //calculam adancimea la care se afla fiecare nod
    calc_dpth(1, 0);
    //cout << "a";
    //acum stramosii cu 2^0 mai sus de fiecare nod sunt calculati. Vom calcula acum
    //stramosii cu toate puterile mai sus, pana la 2^14
    for(int putere = 1; putere < 14; putere++) {
        //cout << "putere " << putere << "\n";
        for(int nod = 1; nod <= n; nod++) {
            //cout << "nod " << nod << ", ";
            //verificam daca ne permite nodul de sus sa avansam (daca nodul cu putere mai sus are putere
            //stramosi, ca poate are doar mai putini)
            if(ancestors[nod].size() >= putere && ancestors[ancestors[nod][putere - 1]].size() >= putere) {
                ancestors[nod].push_back(ancestors[ancestors[nod][putere - 1]][putere - 1]);
            }
        }
    }

    // for(int i = 1; i <= n; i++) {
    //     cout << "\n" << i << ": ";
    //     for(auto it : ancestors[i]) {
    //         cout << it << " ";
    //     }
    // }

    //citim query-urile
    int u, v, dife;
    for(int i = 1; i <= t; i++) {
        fin >> u >> v;
        //cout << i << ": " << u << ", " << v << "\n";
        //aducem u si v pe aceeasi pozitie
        if(dpth[u] < dpth[v]) {
            dife = dpth[v] - dpth[u];
            int putere = 0;
            while(dife > 0) {
                if(dife % 2 == 1) {
                    v = ancestors[v][putere];
                }
                dife /= 2;
                putere++;
            }
        }
        else if(dpth[v] < dpth[u]) {
            //cout << "am intrat cu dife ";
            dife = dpth[u] - dpth[v];
            //cout << dife << "\n";
            int putere = 0;
            while(dife > 0) {
                if(dife % 2 == 1) {
                    u = ancestors[u][putere];
                    putere++;
                }
                dife /= 2;
                putere++;
                //cout << u << "\n";
            }
        }

        //acum nodurile au fost aduse pe aceeasi pozitie
        //incepem cautarea de la cea mai mare putere a lui 2 mai mica su egala
        //cu lungimea vecotrului de ancestori
        //cout << "---" << u << ", " << v << "\n";
        if(u == v) {
            fout << u << "\n";
            continue;
        }
        for(int putere = ancestors[u].size(); putere > 0; putere--) {
            if(ancestors[u][putere - 1] != ancestors[v][putere - 1]) {
                u = ancestors[u][putere - 1];
                v = ancestors[v][putere - 1];
            }
        }
        fout << ancestors[u][0] << "\n";
        
    }
    
    return 0;
}