Cod sursa(job #2560455)

Utilizator AndreiD31Dragan Andrei AndreiD31 Data 28 februarie 2020 00:38:57
Problema Lowest Common Ancestor Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 2.8 kb
#include <bits/stdc++.h>

using namespace std;

ifstream f("lca.in");
ofstream g("lca.out");

vector <int> v[100100];
vector <int> euler,adancime;
int indice,poz[100100];

void parcurgere_euler(int nod,int adancime_nod)
{
    int i;
    indice++;
    if(poz[nod]==0)poz[nod]=indice;

    euler.push_back(nod);
    adancime.push_back(adancime_nod);

    for(i=0;i<v[nod].size();i++)
    {
        int vecin=v[nod][i];

        parcurgere_euler(vecin,adancime_nod+1);

        indice++;
        euler.push_back(nod);
        adancime.push_back(adancime_nod);
    }
}

int n,m,i,N,k,K,x,y,p1,p2,nod_minim,lungime_interval,adancime_minima,dmin[500100][20],dindice[500100][20];
int main()
{
    f>>n>>m;
    for(i=1;i<=n-1;i++)
    {
        f>>x;
        v[x].push_back(i+1);
    }

    /// drumul euler
    parcurgere_euler(1,0);

    /// dinamica dmin[i][k] = adancimea minima din intervalul (i -> i+2^k-1)
    /// dmin tine minimul adancimilor intervalului din vectorul euler
    /// dindice tine pozitiile/nodurile
    N=euler.size();
    for(i=1;i<=N;i++)dmin[i][0]=adancime[i-1],dindice[i][0]=euler[i-1];
    for(k=1;(1<<k)<=N;k++)
    {
        for(i=1;i+(1<<k)-1<=N;i++)
        {
            dmin[i][k]=min(dmin[i][k-1],dmin[i+(1<<(k-1))][k-1]); /// primul face intervalul (i -> i+2^(k-1)-1): asta incepe in capataul stanga
                                                                  /// al doilea face intervalul (i+2^(k-1) -> i+2^(k-1)+2^(k-1)-1) = (i+2^(k-1) -> i+2^k-1): asta se termina in capatul dreapta
                                                                  /// cele doua intervale se completeaza: unde se termina unul, incepe altul => stiu ca iau toate posibilitatile, deci fac dinamica de minim

            if(dmin[i][k-1] < dmin[i+(1<<(k-1))][k-1])dindice[i][k]=dindice[i][k-1];
            else dindice[i][k]=dindice[i+(1<<(k-1))][k-1];
        }
    }

    for(i=1;i<=m;i++)
    {
        f>>x>>y;
        p1=poz[x];
        p2=poz[y];

        /// facem minimul intre p1 si p2
        if(p1>p2)swap(p1,p2);
        lungime_interval=p2-p1+1;

        /// cautam cea mai mare putere a lui 2 <= lungime_interval; fie aceasta K => (p1 + 2^K <= p2)
        K=log2(lungime_interval);

        /// acum cautam solutia impartind intervalul in doua parti, la fel ca la constructia dinamicii, doar ca aici intervalele se intersecteaza
        /// iau intervalul (p1 -> p1+2^K-1)
        /// iau intervalul (p2-2^K+1 -> p2)
        /// cele 2 intervale se intersecteaza (chestia asta se demonstreaza prin comparare)

        adancime_minima=min(dmin[p1][K],dmin[p2-(1<<K)+1][K]);
        if(dmin[p1][K] < dmin[p2-(1<<K)+1][K])nod_minim=dindice[p1][K];
        else nod_minim=dindice[p2-(1<<K)+1][K];

        g<<nod_minim<<'\n';
    }
    return 0;
}