/* Facem o Parcurgere Euler (Euler Tour) a grafului - link util: https://infoarena.ro/lowest-common-ancestor
Retinem adancimea la fiecare nod parcurs, si prima pozitie pe care intalnim un nod
Aplicam RMQ (vezi link-ul de sus) intre nodurile pentru care vrem sa aflam LCA, cu o observatie:
LCA(i, j) = RMQ(prima_pozitie[i], prima_pozitie[j]). Query-ul pentru care cautam minimul este pentru vectorul de adancime
*/
#include <stdio.h>
#include <vector>
using namespace std;
// declaram variabilele necesare pentru RMQ
int minim[18][199999] = {0}, minpos[18][199999];
int tata[100001], prima_poz[100001], adancime[199999], euler[199999];
void tur_euler(int rad, int adanc, int &lungime_parcurgere, int *euler, int *tata, vector <int> *fii, int *prima_poz, int *adancime) {
// verificam si actualizam prima pozitie
if (!prima_poz[rad])
prima_poz[rad] = lungime_parcurgere;
// daca nodul este frunza doar il adaugam
// daca are fii lucrurile se complica: trebuie sa ne intoarcem la radacina dupa fiecare fiu parcurs
for (int i = 0; i < fii[rad].size(); i++) {
adancime[lungime_parcurgere] = adanc;
euler[lungime_parcurgere++] = rad;
tur_euler(fii[rad][i], adanc + 1, lungime_parcurgere, euler, tata, fii, prima_poz, adancime);
}
adancime[lungime_parcurgere] = adanc;
euler[lungime_parcurgere++] = rad;
}
int min(int a, int b) {
if (a > b)
return b;
return a;
}
int RMQ(int l, int r, int *euler, int *adancime) {
// asiguram ca o sa cautam de la stanga la dreapta
if (l > r) {
int aux = l;
l = r;
r = aux;
}
int i, k = 0, sol, solpos;
// calculam cea mai mare putere de 2 pentru care putem sa accesam matricea RMQ
for (i = 1; i <= (r - l); i <<= 1)
k++;
k--;
if (k < 0)
k = 0;
// presupunem ca solutia este in "prima parte", apoi cautam in cealalta bucata
sol = minim[k][l];
solpos = minpos[k][l];
if (sol > minim[k][l + (1 << k)])
solpos = minpos[k][l + (1 << k)];
return euler[solpos];
}
int main() {
freopen("lca.in", "r", stdin);
freopen("lca.out", "w", stdout);
int n, m, lungime_parcurgere = 0, x, y, k = 0;
scanf("%d %d", &n, &m);
vector <int> fii[n + 1];
// adaugam tatii si fii
for (int i = 2; i <= n; i++) {
scanf("%d", &tata[i]);
fii[tata[i]].push_back(i);
}
// parcurgem euler de la radacina trimitand adancimea
tur_euler(1, 0, lungime_parcurgere, euler, tata, fii, prima_poz, adancime);
// calculam logaritm in baza 2 din (2n - 1) pentru construirea matricei de RMQ pe baza vectorului de adancime
for (int i = 1; i <= 2 * n - 1; i <<= 1)
k++;
// initializam prima linie pentru a putea face recurenta
for (int i = 0; i < 2 * n - 1; i++) {
minim[0][i] = adancime[i];
minpos[0][i] = i;
}
// construim restul tabloului pe baza recursivitatii
for (int j = 1; j < k; j++)
for (int i = 0; i < 2 * n - 1; i++)
if (minim[j - 1][i] > minim[j - 1][i + (1 << (j - 1))]) {
minim[j][i] = minim[j - 1][i + (1 << (j - 1))];
minpos[j][i] = minpos[j - 1][i + (1 << (j - 1))];
}
else {
minim[j][i] = minim[j - 1][i];
minpos[j][i] = minpos[j - 1][i];
}
for (int i = 0; i < m; i++) {
scanf("%d %d", &x, &y);
printf("%d\n", RMQ(prima_poz[x], prima_poz[y], euler, adancime));
}
return 0;
}