Cod sursa(job #794204)
#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;
}