Cod sursa(job #3305092)

Utilizator jumaracosminJumara Cosmin-Mihai jumaracosmin Data 29 iulie 2025 20:29:24
Problema Stramosi Scor 90
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 2.46 kb
#include <bits/stdc++.h>

std::ifstream fin("stramosi.in");
std::ofstream fout("stramosi.out");

//#define fin std::cin
//#define fout std::cout

/*
    Binary Lifting //& Liniarizarea arborelui//
    --------------

    Se da un arbore cu radacina cu N noduri si Q intrebari de forma:
        (x, k) - care este cel de-al k-lea stramos al nodului x

    Folosind father[i] si mergand in sus avem O(N) pe query, insa avem nevoie de o complexitate mai buna,
    precum O(log(n)):
        -> binary search <-> nu putem aplica cautarea binara 
        -> divide et impera <-> nu putem combina subprobleme
        -> puteri de 2 

    As putea avea anc[x][i] = al 2^i -lea stramos al nodului x
        -> orice numar k poate fi scris ca suma de puteri de 2

    OBS: Putem construi tabloul in timpul unui DFS sau folosing 2 for-uri (for exp... for node)

    //OBS: Daca avem mai multe arbori putem crea o radacina -1 de care se leaga toate radacinile.
    //     Daca LCA-ul este -1 atunci acesta nu exista.
*/

const int nmax = 250005;
const int lognmax = 19;

int n, q;
std::vector<int> graph[nmax];
int father[nmax];
int lvl[nmax];

int anc[lognmax][nmax];

void dfs(int node, int parent)
{
    anc[0][node] = parent;
    lvl[node] = lvl[parent] + 1;

    for(int i = 1; i < lognmax; ++i)
        anc[i][node] = anc[i - 1][anc[i - 1][node]];

    for(auto adj : graph[node])
        if(adj != parent)
            dfs(adj, node);
}

int query(int node, int k)
{
    if(k >= lvl[node])
        return 0;

    int answer = node;
    for(int i = lognmax - 1; i >= 0; --i)
        if(k >= (1 << i))
            answer = anc[i][answer], k -= (1 << i);

    return answer;
}

int main()
{
    
    fin >> n >> q;
    for(int i = 1; i <= n; ++i)
    {
        fin >> father[i];
        graph[i].push_back(father[i]);
        graph[father[i]].push_back(i);
    }
    /* Metoda 1:

    for(int i = 1; i <= n; ++i)
        anc[0][i] = father[i];

    for(int i = 1; (1 << i) <= n; ++i)
        for(int x = 1; x <= n; ++x)
            anc[i][x] = anc[i - 1][anc[i - 1][x]]; // 2^i = 2^(i - 1) + 2^(i - 1)
    */

    // Metoda 2: (folositoare pentru atunci cand nu exista mereu al k-lea ancestor)

    for(int i = 1; i <= n; ++i)
        if(father[i] == 0) // radacina
            dfs(i, 0);

    for(int i = 1; i <= q; ++i)
    {
        int x, k;
        fin >> x >> k;

        fout << query(x, k) << "\n";
    }

    return 0;
}