Cod sursa(job #1054284)

Utilizator costinbanuCostin Banu costinbanu Data 13 decembrie 2013 17:03:21
Problema Lowest Common Ancestor Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 3.27 kb
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;

/** 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)
    E: vectorul cu nodurile vizitate in parcurgerea Euler
    nrE: nr. elemente ale lui E si L
    Log: vector cu logaritmi precalculati ( Log[i] == floor(log2(i)) )
    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 da un arbore prin vectorul 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
    la citire (lista de adiacenta C).
    -> 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.
    -> RMQ construieste M-ul astfel: M[i][j] = nodul de nivel minim cuprins intre pozitiile
    j si j + (1 << i) - 1 din reprezentarea Euler a arborelui (adica H).
    -> rezultatul unui query (pt. nodurile u si v) este nodul de nivel minim cuprins intre
    H[min(u, v)] si H[max(u, v)].
**/

const int MAX_N = 100005, MAX_L = 20;

int nrE, N, Q;
int L[MAX_N * 2], E[MAX_N * 2], Log[MAX_N * 2], H[MAX_N], M[MAX_L][MAX_N * 4];

vector <int> C[MAX_N];
typedef vector<int>::iterator IT;

void Euler(int nod, int niv) {
    E[++nrE] = nod;
    L[nrE] = niv;
    H[nod] = nrE;
    for(IT i = C[nod].begin(); i != C[nod].end(); i++) {
        Euler(*i, niv + 1);
        E[++nrE] = nod;
        L[nrE] = niv;
    }
}

void RMQ() {
    for(int i = 2; i <= nrE; i++)
        Log[i] = Log[i >> 1] + 1;
    for(int i = 1; i <= nrE; i++)
        M[0][i] = i;
    for(int i = 1; (1 << i) < nrE; i++)
        for(int j = 1; j <= nrE - (1 << i); j++) {
            int l = 1 << (i - 1);
            M[i][j] = M[i-1][j];
            if(L[M[i-1][j + l]] < L[M[i][j]])
                M[i][j] = M[i-1][j + l];
        }
}

int query(int u, int v) {
    int diff, l, sol, sh;
    int a = H[u], b = H[v];
    if(a > b) swap(a, b);
    diff = b - a + 1;
    l = Log[diff];
    sol = M[l][a];
    sh = diff - (1 << l);
    if(L[sol] > L[M[l][a + sh]])
        sol = M[l][a + sh];
    return E[sol];
}

int main() {
    FILE *in = fopen("lca.in", "r"), *out = fopen("lca.out", "w");
    if (in && out) {
        fscanf(in, "%d %d", &N, &Q);
        for(int i = 2; i <= N; i++) {
            int u;
            fscanf(in, "%d", &u);
            C[u].push_back(i);
        }
        Euler(1, 0);
        RMQ();
        for(int i = 0; i < Q; i++) {
            int u, v;
            fscanf(in, "%d %d", &u, &v);
            fprintf(out, "%d\n", query(u, v));
        }
        fclose(in), fclose(out);
    }
    return 0;
}