Cod sursa(job #1838040)

Utilizator BLz0rDospra Cristian BLz0r Data 30 decembrie 2016 21:44:31
Problema Lowest Common Ancestor Scor 0
Compilator cpp Status done
Runda Arhiva educationala Marime 1.7 kb
#include <fstream>
#include <vector>
#include <algorithm>
using namespace std;

#define NMAX 100002
#define LMAX 20

ifstream fin("lca.in");
ofstream fout("lca.out");

vector <int> Arb[NMAX];
int RMQ[LMAX][NMAX<<1], Euler[NMAX<<1], First[NMAX], Nivel[NMAX<<1], lg[NMAX<<1], k, N, M;

// facem o parcurgere Euler a arborelui
void DFS (int nod, int niv) {
    vector <int> :: iterator it;

    Euler[++k] = nod;
    Nivel[k] = niv;
    First[nod] = k;

    for (it = Arb[nod].begin(); it < Arb[nod].end(); ++it) {

        DFS(*it, niv + 1);

        Euler[++k] = nod;
        Nivel[k] = niv;
    }

}

inline int maxLevel(int x, int y) {

    return (Nivel[x] >= Nivel[y] ? x : y);
}

void makeRMQ() {

    // precalc logaritm
    for (int i = 2; i <= k; ++i)
        lg[i] = lg[i>>1] + 1;

    for (int i = 1; i <= k; ++i)
        RMQ[0][i] = i;

    for (int i = 1; (1 << i) < k; ++i) {
        for (int j = 1; j <= k - (1 << i); ++j) {

            int t = (1 << (i - 1));
            RMQ[i][j] = maxLevel(RMQ[i-1][j], RMQ[i-1][j+t]);
        }
    }
}

// LCA-ul a 2 noduri e dat de nodul cu cel mai mic nivel aflat intre ele in parcurgerea euler
int LCA(int x, int y) {

    if (x > y)
        swap(x, y);

    int dif = y - x + 1;
    int a = lg[dif];
    int t = dif - (1 << a);

    int sol = maxLevel(RMQ[a][x], RMQ[a][y-t]);

    return Euler[sol];
}

int main() {

    int x, y;

    fin >> N >> M;

    for (int i = 2; i <= N; ++i) {
        fin >> x;
        Arb[x].push_back(i);
    }

    DFS(1, 0);
    makeRMQ();

    while (M--) {

        fin >> x >> y;

        fout << LCA(First[x], First[y]) << "\n";
    }

    return 0;
}