Pagini recente » Cod sursa (job #889722) | Cod sursa (job #2403187) | Cod sursa (job #2872235) | Cod sursa (job #1490082) | Cod sursa (job #2560455)
#include <bits/stdc++.h>
using namespace std;
ifstream f("lca.in");
ofstream g("lca.out");
vector <int> v[100100];
vector <int> euler,adancime;
int indice,poz[100100];
void parcurgere_euler(int nod,int adancime_nod)
{
int i;
indice++;
if(poz[nod]==0)poz[nod]=indice;
euler.push_back(nod);
adancime.push_back(adancime_nod);
for(i=0;i<v[nod].size();i++)
{
int vecin=v[nod][i];
parcurgere_euler(vecin,adancime_nod+1);
indice++;
euler.push_back(nod);
adancime.push_back(adancime_nod);
}
}
int n,m,i,N,k,K,x,y,p1,p2,nod_minim,lungime_interval,adancime_minima,dmin[500100][20],dindice[500100][20];
int main()
{
f>>n>>m;
for(i=1;i<=n-1;i++)
{
f>>x;
v[x].push_back(i+1);
}
/// drumul euler
parcurgere_euler(1,0);
/// dinamica dmin[i][k] = adancimea minima din intervalul (i -> i+2^k-1)
/// dmin tine minimul adancimilor intervalului din vectorul euler
/// dindice tine pozitiile/nodurile
N=euler.size();
for(i=1;i<=N;i++)dmin[i][0]=adancime[i-1],dindice[i][0]=euler[i-1];
for(k=1;(1<<k)<=N;k++)
{
for(i=1;i+(1<<k)-1<=N;i++)
{
dmin[i][k]=min(dmin[i][k-1],dmin[i+(1<<(k-1))][k-1]); /// primul face intervalul (i -> i+2^(k-1)-1): asta incepe in capataul stanga
/// al doilea face intervalul (i+2^(k-1) -> i+2^(k-1)+2^(k-1)-1) = (i+2^(k-1) -> i+2^k-1): asta se termina in capatul dreapta
/// cele doua intervale se completeaza: unde se termina unul, incepe altul => stiu ca iau toate posibilitatile, deci fac dinamica de minim
if(dmin[i][k-1] < dmin[i+(1<<(k-1))][k-1])dindice[i][k]=dindice[i][k-1];
else dindice[i][k]=dindice[i+(1<<(k-1))][k-1];
}
}
for(i=1;i<=m;i++)
{
f>>x>>y;
p1=poz[x];
p2=poz[y];
/// facem minimul intre p1 si p2
if(p1>p2)swap(p1,p2);
lungime_interval=p2-p1+1;
/// cautam cea mai mare putere a lui 2 <= lungime_interval; fie aceasta K => (p1 + 2^K <= p2)
K=log2(lungime_interval);
/// acum cautam solutia impartind intervalul in doua parti, la fel ca la constructia dinamicii, doar ca aici intervalele se intersecteaza
/// iau intervalul (p1 -> p1+2^K-1)
/// iau intervalul (p2-2^K+1 -> p2)
/// cele 2 intervale se intersecteaza (chestia asta se demonstreaza prin comparare)
adancime_minima=min(dmin[p1][K],dmin[p2-(1<<K)+1][K]);
if(dmin[p1][K] < dmin[p2-(1<<K)+1][K])nod_minim=dindice[p1][K];
else nod_minim=dindice[p2-(1<<K)+1][K];
g<<nod_minim<<'\n';
}
return 0;
}