Cod sursa(job #2535324)

Utilizator mihailescu_eduardMihailescu Eduard-Florin mihailescu_eduard Data 31 ianuarie 2020 19:14:08
Problema Lowest Common Ancestor Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.65 kb
//#pragma GCC optimize ("O3")
//#pragma GCC target ("sse4")

#include <bits/stdc++.h>

using namespace std;

#define sim template < class c
#define ris return * this
#define dor > debug & operator <<
#define eni(x) sim > typename \
  enable_if<sizeof dud<c>(0) x 1, debug&>::type operator<<(c i) {
sim > struct rge { c b, e; };
sim > rge<c> range(c i, c j) { return rge<c>{i, j}; }
sim > auto dud(c* x) -> decltype(cerr << *x, 0);
sim > char dud(...);
struct debug {
#ifdef LOCAL
~debug() { cerr << endl; }
eni(!=) cerr << boolalpha << i; ris; }
eni(==) ris << range(begin(i), end(i)); }
sim, class b dor(pair < b, c > d) {
  ris << "(" << d.first << ", " << d.second << ")";
}
sim dor(rge<c> d) {
  *this << "[";
  for (auto it = d.b; it != d.e; ++it)
    *this << ", " + 2 * (it == d.b) << *it;
  ris << "]";
}
#else
sim dor(const c&) { ris; }
#endif
};
#define imie(...) " [" << #__VA_ARGS__ ": " << (__VA_ARGS__) << "] "


// CHECK THE LIMITS
typedef long long ll;

const int MOD = 1000000007;
const ll INFLL = 1e18;
const int INF = 1e9;
const int NMAX = 100005;
const int K = 20;

int gcd(int a, int b) {
  return b ? gcd(b, a%b) : a;
} 

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

int n,m;

// H[i] - reprezentarea grafului sub forma euler H[i] nodul de pe poz i in reprezentare
// L[i] - nivelul la care se afla nodul i;
// LG[i] - log2 din i ne ajuta la rmq
// First[i] - prima aparitie a nodului i in reprezentarea euler
// sp[NMAX][k] sparse table calculeaza rmq 

int L[NMAX*2], H[NMAX*2], LG[NMAX*2], First[NMAX];
int sp[NMAX*2][K];
bool visited[NMAX];
vector<int> G[NMAX];
int p = -1;


void dfs(int node, int level)
{
    H[++p] = node;
    L[p] = level;
    First[node] = p; 
    
    for(auto &child : G[node])
    {
        dfs(child,level+1);
        H[++p]=node;
        L[p] = level;
    }
}

void construct_log()
{
    LG[1] = 0;
    for(int i =2 ; i<= p; ++i)
    {
        LG[i] = LG[i>>1] + 1;
    }
}


void construct_rmq()
{
    // construct logarithm array;
    construct_log();

    for(int i = 0; i<= p; ++i)
    {
        sp[i][0] = i;
    }


    for(int j = 1; j <= K; j++)
    {
        for(int i = 0; i + (1 << j) <= p; ++i)
        {
            int levelFirst = L[sp[i][j-1]];
            int levelSecond = L[sp[i + (1 << (j-1))][j-1]];
            if(levelFirst < levelSecond)
            {
                sp[i][j] = sp[i][j-1];
            }
            else
            {
                sp[i][j] = sp[i + (1 << (j-1))][j-1];
            }
        }
    }
}

int lca(int left, int right)
{
    int first_left = First[left];
    int first_right = First[right];
    
    // swap them depending of the order in euler representation
    if(first_right < first_left)
    {
        int aux = first_left;
        first_left = first_right;
        first_right = aux;
    }

    int j = LG[first_right - first_left + 1];

    int index =0;
    if(L[sp[first_left][j]] < L[sp[first_right - (1<<j) + 1][j]])
        index = sp[first_left][j];
    else
        index = sp[first_right - (1<<j) + 1][j];

    return H[index];
}

 
int main()
{
    ios_base::sync_with_stdio(0);
    cin.tie(0);

    
    fin >> n >> m;
    for(int i = 1; i< n; ++i)
    {
        int x;
        fin >> x;
        x--;
        G[x].push_back(i);
    }

    // TODO
    // de calculat reprezentarea euler si pentru fiecare nod sa ii retin nivelul
    dfs(0,0);
    construct_rmq();

    // pentru fiecare query sa fac rmq intre H[first[left]] si H[first[right]]
    // sparse tabelul pentru rmq tine minte indexul nivelului minim
    for(int i =0; i < m; ++i)
    {
        int left, right;
        fin >> left >> right;

        left--;right--;
        fout << lca(left,right)+1 << '\n';
    }

    


    return 0;
}