Cod sursa(job #1054011)

Utilizator costinbanuCostin Banu costinbanu Data 13 decembrie 2013 10:41:49
Problema Lowest Common Ancestor Scor 0
Compilator cpp Status done
Runda Arhiva educationala Marime 4.06 kb
#include<cstdio>
#include<cmath>
#include<cstdlib>
using namespace std;

struct nod {
    int val;
    nod *next;
} *C[100000];

int M[100000][17], N, Q, T[100000], E[200001], nrE, rad, H[200001], L[200001], 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;
}