Cod sursa(job #3235505)

Utilizator PetstebPopa Petru Petsteb Data 18 iunie 2024 10:24:42
Problema Lowest Common Ancestor Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.38 kb
// varianta Alex Turculet
#include <fstream>
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;

const int NMAX = 100005;
const int LMAX = 20;

int k, n, m;
int nivel[NMAX << 1], euler[NMAX << 1], prima_apar[NMAX]; // euler tur- 2*nr muchii

vector<int> G[NMAX];

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

void parcurg(int nod, int niv_curent)
{
    k = k + 1;
    euler[k] = nod;
    nivel[k] = niv_curent;
    prima_apar[nod] = k;

    for (auto it : G[nod])
    {
        parcurg(it, niv_curent + 1);

        k = k + 1;
        euler[k] = nod;
        nivel[k] = niv_curent;
    }
}

// const int NMAX = 1e5;
// int a[NMAX + 1],n;
int rmq[NMAX << 1][20]; // rmq[lungime vector][cea mai mare putere a lui 2 cane nu depaseste lungimea]
// int LOG[NMAX + 1];
void preproc_rmq()
{
    /*programare dinamica
    rmq[i][j]=pozitia mininului pentru secventa care
              incepe pe pozitia i si are lungime 2^j
    */

    // stim direct: pentru j=0, adica secvente de lungime 2^0=1
    for (int i = 0; i <= k; i++)
    {
        rmq[i][0] = i;
    }

    /*
     * relatia de recurenta- reducem secvente de lungime 2^j la secvente de lungime 2^{j-1},
     * mai exact, pentru a calcula rmq[i][j]
     * impartim secventa de lungime 2^j care incepe pe pozitia i in doua de lungime 2^{j-1} :
     * => doua subsecvente mai mici, una incepe pe pozitia i si cealalta pe i+2^{j-1}
     * pentru care min este deja calculat
     * Min pentru intreaga secventa(Deci rmq[i][j] este minimul dintre minimele celor doua subsecvente
     *  =>rmq[i][j] va fi  min(a[rmq[i][j-1]], a[rmq[i][i+2^{j-1} ]}
     */
    // ordine de calcul-crescator dupa lungime, pentru 2^j<=n
    for (int j = 1; (1 << j) <= k; j++)
        for (int i = 0; i + (1 << j) - 1 < k; i++)
            if (nivel[rmq[i][j - 1]] < nivel[rmq[i + (1 << (j - 1))][j - 1]])
                rmq[i][j] = rmq[i][j - 1];
            else
                rmq[i][j] = rmq[i + (1 << (j - 1))][j - 1];
}

int query(int x, int y)
{
    // determinam k maxim cu 2^k<=lungimea secventei x,x+1,...y:
    /*consideram doua secvente de lungime 2^{k-1} care acopera secventa noastra:
    una in stanga, care incepe pe pozitia x,
     una in dreapta, care se termina pe pozitia y, deci incepe pe y - (1 << k) + 1
     */

    int k2 = log2(y - x + 1);
    // mai bine:
    // int k=lg[y-x+1]; //unde lg - vector in care am precalculat log2 cu relatia de recurenta lg[i] = lg[i / 2] + 1;
    if (nivel[rmq[x][k2]] < nivel[rmq[y - (1 << k2) + 1][k2]])
        return rmq[x][k2];
    return rmq[y - (1 << k2) + 1][k2];
}

int main()
{
    // cout << "Hellow rodl";
    int x, y;
    fin >> n >> m;

    for (int i = 2; i <= n; i++)
    {
        fin >> x;
        G[x].push_back(i);
    }
    k = -1;
    parcurg(1, 0);
    /*for (int i = 0; i <= k; i++)
        cout<<euler[i]<<" ";
    cout<<"\n";
    for (int i = 0; i <= k; i++)
        cout<<nivel[i]<<" ";
    cout<<"\n";*/

    preproc_rmq();

    for (int j = 1; j <= m; j++)
    {
        fin >> x >> y;
        // cout << x << " " << y << ' ';
        // cout << prima_apar[x] << " " << prima_apar[y] << endl;
        if (prima_apar[x] > prima_apar[y])
            swap(x, y);
        // cout << query(prima_apar[x], prima_apar[y]) << " ";
        fout << euler[query(prima_apar[x], prima_apar[y])] << endl;
    }
}