Pagini recente » Cod sursa (job #1496908) | Cod sursa (job #237154) | Cod sursa (job #2916122) | Cod sursa (job #230630) | Cod sursa (job #790148)
Cod sursa(job #790148)
#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 inf (1<<29)
int n, m, v[2*nmax], P[nmax], nivel[nmax], Min[17][nmax], Poz[17][nmax], Exp[nmax];
vector<int> gf[nmax];
void citeste(){
f >> n >> m;//numarul de noduri; numarul de query-uri
for(int i=1; i<n; ++i){
int x;
f >> x;
gf[x].push_back(i+1);
}
}
void dfs(int nod, int niv){
v[ ++v[0] ] = nod;
P[nod] = v[0];
nivel[nod] = niv;
for(int i=0; i<gf[nod].size(); ++i){
int vc = gf[nod][i];
dfs(vc, niv+1);
v[ ++v[0] ] = nod;
}
}
void preprocesare(){
for(int i=0; i<=17; ++i) for(int j=1; j<=n; ++j) Min[i][j] = inf;
for(int i=1; i<=v[0]; ++i) Min[0][i] = nivel[ v[i] ], Poz[0][i] = i;
for(int i=1; i<=17; ++i){
for(int j=1; (j+(1<<i)-1)<=v[0]; ++j){
int dr = j + (1<<i) - 1;//capatul dreapta al intervalului ocupat de pozitia j
//acum caut o pozitie new_X a. i. new_X + (1<<(i-1)) -1 == dr
int new_X = dr - (1<<(i-1)) + 1;
//initial presupun ca minimul se afla pe intervalul [j, j+(1<<(i-1))-1]
Min[i][j] = Min[i-1][j];
Poz[i][j] = Poz[i-1][j];
//acum vreau sa vad daca exista un element mai mic pe intervalul [new_X, new_X+(1<<(i-1))-1]
if (Min[i][j] > Min[i-1][new_X]){
Min[i][j] = Min[i-1][new_X];
Poz[i][j] = Poz[i-1][new_X];
}
}
}
}
void scrie(){
for(int i=1; i<=v[0]; i++) g << v[i] << " ";
g << "\n";
for(int i=1; i<=v[0]; ++i) g<< nivel[ v[i] ] << " ";
g << "\n";
}
void rezolva(){
//aflu lca-ul cu rmq
//fac o parcurgere euler a arborelui
dfs(1, 1);
//acum am v[] care imi da secventa euler si fac preprocesare pe aceasta secventa imi fac Min[i][j] = minimul de pe intervalul [j, j+(2^i)-1]
//si mai tin minte Poz[i][j] = X, unde X e pozitie pe care se afla acest minin(in secventa euler)
//scrie();
preprocesare();
Exp[1] = 0;
for(int i=2; i<=v[0]; ++i) Exp[i] = Exp[i/2] + 1;
for(int i=1; i<=m; ++i){
int x, y;
f >> x >> y;
//acum Lca-ul celor doua noduri va fi dat de nodul cu cel mai mic nivel de pe intervalul P[x], P[y]
x = P[x]; y = P[y];
if (x > y ) swap(x,y);
//aflu minimul in o(1)
//iau initial intervalul x, x+(1<<k)-1 si apoi minimul de pe intervalul [x+ceva, x+ceva+(1<<k)-1]
int lung = y-x+1;
int k = Exp[lung];
int rez = Min[k][x];
int lca = v[ Poz[k][x] ];
//acum trebuie sa caut o noua pozitie(fie aceasta Y) a. i. Y + (1<<i)-1 == y;
int new_X = y - (1<<k) +1;
if (rez > Min[k][new_X]){
rez = Min[k][new_X];
lca = v[ Poz[k][new_X] ];
}
g << lca << "\n";
}
}
int main(){
citeste();
rezolva();
f.close();
g.close();
return 0;
}