Pagini recente » Cod sursa (job #525752) | Cod sursa (job #2918160) | Cod sursa (job #1904695) | Cod sursa (job #1199835) | Cod sursa (job #1054023)
#include<cstdio>
#include<cmath>
#include<cstdlib>
using namespace std;
struct nod {
int val;
nod *next;
} *C[100002];
int M[100002][17], N, Q, T[100002], E[200002], nrE, rad, H[200002], L[200002], u, v;
/** http://community.topcoder.com/tc?module=Static&d1=tutorials&d2=lowestCommonAncestor
NOTATII (ca in articol)
-----------------------
C: lista de fii a arborelui
M: dinamica pt. RMQ
N: nr. noduri
Q: nr. intrebari (query-uri)
T: vectorul de tati
E: vectorul cu nodurile vizitate in parcurgerea Euler
nrE: nr. elemente ale lui E si L
rad: radacina arborelui
H: H[i] este primul index al nodului i in E
L: L[i] este nivelul nodului E[i]
u, v: se citesc Q intrebari de forma "care este LCA al nodurilor u si v?"
FUNCTIONARE
-----------
-> Se citeste un arbore dat ca vector de tati. Parcurgerea Euler presupune
vizitarea unui fiu plecand din tatal sau, ceea ce un vector de tati nu permite.
-> Daca fiecare nod ar avea acelasi numar de fii atunci s-ar putea reprezenta
ca un heap. In cazul general este necesara lista de fii. Aceasta se construieste
in O(N).
-> Parcurgerea Euler va construi un vector de noduri vizitate ( E in program ) cu
2*N-1 elemente ( nrE in program ). Pe lista de fii, aceasta se realizeaza in timp
liniar ( O(nrE) ).
-> O data cu vectorul E se construiesc si vectorii L si H pe care se realizeaza RMQ.
**/
void makelist() {
for(int i = 1; i <= N; i++) { ///push nodul i in stiva C[T[i]] (i este unul din copiii lui T[i])
nod *t = (nod *) malloc(sizeof(nod));
t->val = i;
t->next = C[T[i]];
C[T[i]] = t;
}
}
void Euler(int i, int level) { ///parcurgere Euler in arbore retinuta in vectorul E cu nrE elemente
E[++nrE] = i;
L[nrE] = level;
if (H[i] == 0) H[i] = nrE;
if (C[i]) {
Euler(C[i]->val, level + 1);
E[++nrE] = i;
L[nrE] = level;
while (C[i]->next) {
C[i] = C[i] -> next;
Euler(C[i]->val, level + 1);
}
}
}
void RMQ() { /// dinamica RMQ pe vectorul de nivele L care are nrE elemente
int i, j;
for (i = 1; i <= nrE; i++)
M[i][0] = i;
for (j = 1; 1 << j <= nrE; j++)
for (i = 1; i + (1 << j) - 1 <= nrE; i++)
if (L[M[i][j - 1]] < L[M[i + (1 << (j - 1))][j - 1]])
M[i][j] = M[i][j - 1];
else
M[i][j] = M[i + (1 << (j - 1))][j - 1];
}
int query(int i, int j) { /// RMQ adaptat vectorilor
int k = (int) log2(j - i + 1);
if ( L[M[i][k]] <= L[M[j - (1 << k) + 1][k]] ) return M[i][k];
else return M[j - (1 << k) + 1][k];
}
int main() {
FILE *in = fopen("lca.in", "r"), *out = fopen("lca.out", "w");
if (in && out) {
fscanf(in, "%d %d", &N, &Q); /// citire nr. noduri, nr. intrebari
for (int i = 2; i <= N; i++) {
fscanf(in, "%d", T + i); /// citire vectorul de tati
if (T[i] == 0) rad = i; ///este necesar sa identificam radacina aici, pt. optimizare
}
makelist(); /// se construieste lista de fii
Euler(rad, 0); /// se construieste vectorul E cu nodurile arborelui in parcurgerea Euler
RMQ(); /// se construieste dinamica RMQ pe vectorul de nivele L
for (int i = 0; i < Q; i++) { /// citim intrebarile
fscanf(in, "%d %d", &u, &v);
if (H[u] >= H[v]) { /// daca u apare dupa v, atunci trebuie inversate
int shp = u;
u = v;
v = shp;
}
fprintf(out, "%d\n", E[query(H[u], H[v])]); /// raspunsul la intrebare
}
/** cum arata E, L, H:
printf("\n");
for(int i = 1; i <= nrE; i++)
printf("%2d ", E[i]);
printf("\n");
for(int i = 1; i <= nrE; i++)
printf("%2d ", L[i]);
printf("\n");
for(int i = 1; i <= N; i++)
printf("%2d ", H[i]);
*/
fclose(in), fclose(out);
}
return 0;
}