Cod sursa(job #794204)

Utilizator vendettaSalajan Razvan vendetta Data 5 octombrie 2012 22:45:37
Problema Lowest Common Ancestor Scor 70
Compilator cpp Status done
Runda Arhiva educationala Marime 2.98 kb
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <set>
#include <queue>
#include <deque>

using namespace std;

ifstream f("lca.in");
ofstream g("lca.out");

#define nmax 100005
#define ll long long
#define Logn 18

int n, m, tata[Logn][nmax], nivel[nmax];
vector<int> gf[nmax];

void citeste(){

    f >> n >> m;

	for(int i=1; i<n; ++i){
        int x;
        f >> x;
        gf[x].push_back(i+1);
	}

}

void dfs(int nod, int niv){

    //graful e orientat
    nivel[nod] = niv;
    for(int i=0; i<gf[nod].size(); ++i){
        int vc = gf[nod][i];
        tata[0][vc] = nod;
        dfs(vc, niv+1);
    }

}

void fa_tati(){

    for(int i=1; i<=17; ++i){
        for(int j=1; j<=n; ++j){
            int X = tata[i-1][j];
            tata[i][j] = tata[i-1][X];
        }
    }

}

void afla_lca(int x, int y){

    if (x == y){
        g << x << "\n";
        return;
    }

    for(int i=17; i>=0; --i){
        if (tata[i][y] == 0 || tata[i][x] == 0) continue;//daca nu am asa de sus tata;(e de ajuns doar la unul sa vad pt ca sunt pe acelasi nivel)
        if (tata[i][x] == tata[i][y]){//daca au acelasi lca => ma duc mai jos
            continue;
        }
        if (tata[i][x] != tata[i][y]){//daca gasesc o putere la care dau tati diferiti => lca va fi in intervalul 2^i, 2^(i+1)
            x = tata[i][x];
            y = tata[i][y];
        }
    }

    //acum la sfarsit x-ul va fi priuml nod de sub lca pt ca la linia 68 in acel if x si y-ul tin minte fiecare primul nod(de dupa lca) care nu e lca
    //=> Lca-ul va fi primul tata al lui x sau y
    g << tata[0][x] << "\n";

}

void rezolva(){

    //ideea ar fi asa : aduc ambele noduri pe acelasi nivel;
    //apoi incep si caut lca-ul; incepand cu cel mai indepartat tata;
    // ar fi asa iau fiecare tata 2^ksi daca e lca : daca e lca atunci incerc o putere mai mica
    //daca nu e lca atunci mut x,y in acest doi noduri si caut in continuare dupa procedeul de mai sus

    dfs(1,1);
    fa_tati();

    for(int i=1; i<=m; ++i){
        int x, y;
        f >> x >> y;
        //acum le aduc pe acelasi nivel;
        //eu am nevoie de lca => pot inversa nodurile (mai reduc din if-uri) => presuspun tot timpul ca nodul cu nivelul mai mare va fi nodul x-ul
        //adica tot timpul voi aduce nodul x la nivelul nodului y
        if (nivel[x] == nivel[y]){//daca au deja acelsi nivel
            afla_lca(x,y);
            continue;
        }
        if (nivel[x] < nivel[y]) swap(x,y);
        //acum aduc nodul x pe nivelul nodului y;
        //si pentru asta am nevoie de al (nivel[x] - nivel[y])-lea al lui x tata
        int cat = nivel[x] - nivel[y];
        for(int i=17; i>=0; --i){
            if ( ( cat & (1<<i)) != 0 )
                x = tata[i][x];
        }
        //acum am ambele noduri pe acelsi nivel

        afla_lca(x,y);
    }

}

int main(){

    citeste();
    rezolva();

    f.close();
    g.close();

    return 0;

}