Cod sursa(job #2105635)

Utilizator mariusmagureanmagurean marius mariusmagurean Data 13 ianuarie 2018 19:24:25
Problema Lowest Common Ancestor Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 3.03 kb
/*
lowest common ancestor
Solutie 70p

Vom folosi o matrice in care pentru fiecare nod vom retine stramosul situat cu 2^k nivele mai sus, unde 2^k<=n
Matricea va avea k linii si n coloane
Ea va fi notata a si va fi construita dinamic dupa formula
a[0][i]=i, unde i=1...n
a[k][i]=a[k-1][a[k-1][i]], i=1...n si k=1...logn

Cu alte cuvinte vom imparti inaltimea fiecarui nod in intervale puteri ale lui 2.
De exemplu daca un arbore are 10 noduri, ptr nodul 5 se vor retine stramosii situati cu 1 nivel mai sus, 2 nivele, 4 nivele, 8 nivele
Daca un stramos nu exista se va retine 0.

Pentru a gasi lca, vom inainta mai intai in matrice cu nodul de cel mai mare nivel
pana cand va ajunge pe acelasi interval(linie) cu al doilea. Daca am ajuns chiar in al doilea nod, avem raspunsul

Apoi vom inainta cu amandoi doar daca avem stramos pe acel nivel si nu este comun.
In final stramosul de pe linia 0 este raspunsul

Matricea fiilor o memoram in arb

Cu o parcurgere in adancime gasim nivelul fiecarui nod si il retinem in matricea nivel

Complexitate timp: dfs O(n), formarea matricei a in (n*log n), fiecare interogare in timp logaritmic O(log n),
in final O(n*log n) + O(m*log n), unde m este numarul de interogari

Complexitate spatiu : O(n*log n), marimea matricei a
*/

#include<fstream>
#include<vector>

#define dim 100005

using namespace std;

int nivel[dim],a[20][dim];
vector<int>arb[dim];
int n,m;

ifstream fin("lca.in");
ofstream fout("lca.out");

void citire()
{
    int i,j;
    fin>>n>>m;
    for(i=2;i<=n;i++)
    {
        fin>>j;
        a[0][i]=j;
        arb[j].push_back(i);
    }
}

void dfs(int nod,int niv)
{
    nivel[nod]=niv;
    for(vector<int>::iterator it=arb[nod].begin();it!=arb[nod].end();it++)
        dfs(*it,niv+1);
}

int lca(int x, int y)
{
    int i,powerx,powery;
    //vedem care nod este pe un nivel mai mare si il retinem in x
    //pp ca este x
    //daca este y interschimb
    if(nivel[x]<nivel[y])
        x=x+y, y=x-y,x=x-y;
    //trebuie sa stim de unde pornim explorarea in matrice, de pe ce linie
    //calculam puterea maxima a lui 2 fata de nivelul lui x, respectiv y si retinem in powerx si powery
    powerx=1;
    while((1<<powerx)<nivel[x])
        powerx++;
    powery=1;
    while((1<<powery)<nivel[y])
        powery++;
    //aducem x pe acelasi interval cu y
    for(i=powerx;i>=0;i--)
        if(nivel[x]-(1<<i)>=nivel[y])
            x=a[i][x];
    //daca am ajuns in y avem stramosul comun de nivel maxim
    if(x==y)
        return x;
    //gasim stramosul comun
    for(i=powery;i>=0;i--)
        if(a[i][x]!=0 && a[i][x]!=a[i][y])
        {
            x=a[i][x];
            y=a[i][y];
        }
    return a[0][x];
}

int main()
{
    int i,k,x,y;
    citire();
    dfs(1,0);
    //construim matricea a
    for(k=1;(1<<k)<=n;k++)
        for(i=1;i<=n;i++)
            a[k][i]=a[k-1][a[k-1][i]];
    //realizam cele m query
    for(i=1;i<=m;i++)
    {
        fin>>x>>y;
        fout<<lca(x,y)<<"\n";
    }
    return 0;
}