Cod sursa(job #3197757)

Utilizator AbRobertAbabei Robert-Petronel AbRobert Data 27 ianuarie 2024 13:34:16
Problema Lowest Common Ancestor Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 1.8 kb
#include <bits/stdc++.h>
using namespace std;

/**
e = retinem parcurgerea Euler
niv[i] = pe ce nivel se afla nodul e[i]
  in arbore
P[i] = o pozitie unde se afla nodul i in e

rmq[i][j] = valoarea minima din niv[j..j+2^i-1]
i=0..log2(m)
j = 1..m-2^i+1

expo[i] = p: exponentul maxim p cu 2^p<=i

       1 2 3 4 5 6 7 8 9 10 ... 15 16
expo = 0 1 1 2 2 2 2 3 3  3      3  4
*/

ifstream fin("lca.in");
ofstream fout("lca.out");
vector<int> L[100002];
int n, m;
int e[200009], niv[200009], P[100002];
int rmq[20][200009];
int expo[200009];

void Euler(int k, int level)
{
    e[++m] = k;
    niv[m] = level;
    P[k] = m;
    for (int i : L[k])
    {
        Euler(i, level + 1);
        e[++m] = k;
        niv[m] = level;
    }
}

int main()
{
    int i, j, Q, x, A, B, nod, w;
    fin >> n >> Q;
    for (i = 2; i <= n; i++)
    {
        fin >> j;
        L[j].push_back(i);
    }
    Euler(1, 1);
    /// construim expo[]:
    expo[1] = 0;
    for (i = 2; i <= m; i++)
        expo[i] = 1 + expo[i / 2];

    ///rmq:
    for (i = 1; i <= m; i++)
        rmq[0][i] = i;
    for (i = 1; i <= expo[m]; i++)
    {
        /// calculam minimele pe toate secv.
        /// de lungime 2^i
        x = (1 << i);
        for (j = 1; j <= m - x + 1; j++)
        {
            A = rmq[i-1][j];
            B = rmq[i-1][j+x/2];
            if (niv[A] <= niv[B])
                rmq[i][j] = A;
            else rmq[i][j] = B;
        }
    }
    while (Q--)
    {
        fin >> i >> j;
        i = P[i];
        j = P[j];
        if (i > j) swap(i, j);
        w = expo[j-i+1];
        x = (1 << w);
        A = rmq[w][i];
        B = rmq[w][j-x+1];
        if (niv[A] <= niv[B]) x = A;
        else x = B;
        fout << e[x] << "\n";
    }
    return 0;
}