Pagini recente » Cod sursa (job #1199704) | Cod sursa (job #1967329) | Cod sursa (job #2881150) | Cod sursa (job #635429) | Cod sursa (job #3235505)
// varianta Alex Turculet
#include <fstream>
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
const int NMAX = 100005;
const int LMAX = 20;
int k, n, m;
int nivel[NMAX << 1], euler[NMAX << 1], prima_apar[NMAX]; // euler tur- 2*nr muchii
vector<int> G[NMAX];
ifstream fin("lca.in");
ofstream fout("lca.out");
void parcurg(int nod, int niv_curent)
{
k = k + 1;
euler[k] = nod;
nivel[k] = niv_curent;
prima_apar[nod] = k;
for (auto it : G[nod])
{
parcurg(it, niv_curent + 1);
k = k + 1;
euler[k] = nod;
nivel[k] = niv_curent;
}
}
// const int NMAX = 1e5;
// int a[NMAX + 1],n;
int rmq[NMAX << 1][20]; // rmq[lungime vector][cea mai mare putere a lui 2 cane nu depaseste lungimea]
// int LOG[NMAX + 1];
void preproc_rmq()
{
/*programare dinamica
rmq[i][j]=pozitia mininului pentru secventa care
incepe pe pozitia i si are lungime 2^j
*/
// stim direct: pentru j=0, adica secvente de lungime 2^0=1
for (int i = 0; i <= k; i++)
{
rmq[i][0] = i;
}
/*
* relatia de recurenta- reducem secvente de lungime 2^j la secvente de lungime 2^{j-1},
* mai exact, pentru a calcula rmq[i][j]
* impartim secventa de lungime 2^j care incepe pe pozitia i in doua de lungime 2^{j-1} :
* => doua subsecvente mai mici, una incepe pe pozitia i si cealalta pe i+2^{j-1}
* pentru care min este deja calculat
* Min pentru intreaga secventa(Deci rmq[i][j] este minimul dintre minimele celor doua subsecvente
* =>rmq[i][j] va fi min(a[rmq[i][j-1]], a[rmq[i][i+2^{j-1} ]}
*/
// ordine de calcul-crescator dupa lungime, pentru 2^j<=n
for (int j = 1; (1 << j) <= k; j++)
for (int i = 0; i + (1 << j) - 1 < k; i++)
if (nivel[rmq[i][j - 1]] < nivel[rmq[i + (1 << (j - 1))][j - 1]])
rmq[i][j] = rmq[i][j - 1];
else
rmq[i][j] = rmq[i + (1 << (j - 1))][j - 1];
}
int query(int x, int y)
{
// determinam k maxim cu 2^k<=lungimea secventei x,x+1,...y:
/*consideram doua secvente de lungime 2^{k-1} care acopera secventa noastra:
una in stanga, care incepe pe pozitia x,
una in dreapta, care se termina pe pozitia y, deci incepe pe y - (1 << k) + 1
*/
int k2 = log2(y - x + 1);
// mai bine:
// int k=lg[y-x+1]; //unde lg - vector in care am precalculat log2 cu relatia de recurenta lg[i] = lg[i / 2] + 1;
if (nivel[rmq[x][k2]] < nivel[rmq[y - (1 << k2) + 1][k2]])
return rmq[x][k2];
return rmq[y - (1 << k2) + 1][k2];
}
int main()
{
// cout << "Hellow rodl";
int x, y;
fin >> n >> m;
for (int i = 2; i <= n; i++)
{
fin >> x;
G[x].push_back(i);
}
k = -1;
parcurg(1, 0);
/*for (int i = 0; i <= k; i++)
cout<<euler[i]<<" ";
cout<<"\n";
for (int i = 0; i <= k; i++)
cout<<nivel[i]<<" ";
cout<<"\n";*/
preproc_rmq();
for (int j = 1; j <= m; j++)
{
fin >> x >> y;
// cout << x << " " << y << ' ';
// cout << prima_apar[x] << " " << prima_apar[y] << endl;
if (prima_apar[x] > prima_apar[y])
swap(x, y);
// cout << query(prima_apar[x], prima_apar[y]) << " ";
fout << euler[query(prima_apar[x], prima_apar[y])] << endl;
}
}