Cod sursa(job #2069805)

Utilizator Andreiii500Andrei Puiu Andreiii500 Data 18 noiembrie 2017 20:32:38
Problema Lowest Common Ancestor Scor 30
Compilator cpp Status done
Runda Arhiva educationala Marime 3.74 kb
#include<bits/stdc++.h>
#include<iostream>
#include<fstream>
#include<cassert>
#include<cmath>
using namespace std;

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

const int N = 100000;
const int NLOG = 17 + 1; /// +1 Because we want to include level 0 too!

void array_to_RMQ_matrix(int v[], int n, int rmq[][N], int MAX_LEVEL){ /// Creates min() RMQ table "rmq" from Array "v"
    /// Compute RMQ level 0
    for(int i=0; i<n; ++i)
        rmq[0][i] = v[i];

    /// Compute RMQ levels 1 to MAX_LEVEL
    for(int level = 1; level <= 17; ++level)
    {
        int sequence_length = 1 << level;
        int last_sequence_index = n - sequence_length + 1;

        for(int index = 0; index < last_sequence_index; ++index)
            rmq[level][index] = min(rmq[level-1][index], rmq[level-1][index + sequence_length / 2]);

        //for(int index = 0; index < last_sequence_index; ++index) cout<<rmq[level][index]<<" "; cout<<"\n";
    }
}

int MSD(int x){ /// Base 2 MSD of number X
    while(x & (x-1)) /// X isn't a power of 2 yet
        x &= x-1; /// Remove X's LSD

    return x;
}

int rmqArray[NLOG][N]; /// rmqArray[level][index] = min(index, index+1, ..., index + 2^level);
int n;

int queryRMQ(int a, int b){ /// Queries the RMQ table in interval [a, b]
    int query_interval_length = b-a+1;
    int sequence_length = MSD(query_interval_length); /// The maximal RMQ sequence length we can query
    int level = log2(sequence_length);
    int offset = query_interval_length - sequence_length;

    return min(rmqArray[level][a], rmqArray[level][a + offset]); /// min <- [a, a + 2^level] U [a+offset, b]
}

int LMRM_values[2*N]; /// Left - Middle - Right - Middle
list<int> sons[N]; /// sons[x] = sons of node 'x'
int LMRM_length;

int pas = 1;
int maxPas = 10002;

void LMRM_path(int crtNode){
    if(pas >= maxPas) return;
    ++pas;
    LMRM_values[LMRM_length++] = crtNode;
    for(list<int>::iterator it = sons[crtNode].begin(); it != sons[crtNode].end(); ++it){
        LMRM_path(*it);
        if(pas >= maxPas) return;
        LMRM_values[LMRM_length++] = crtNode;
    }
}

int main()
{
    cout<<sizeof(list<int>::iterator)<<" ";
    /// Local Variables
    int first_index[N]; /// first_index[i] = the index where number 'i' appears first in the array
    int q;

    /// Unit Testing :D
    assert(MSD(16) == 16); /// 10000
    assert(MSD(9) == 8);   /// 01001
    assert(MSD(7) == 4);   /// 00111

    /// Input
    in>>n>>q;
    for(int currNode=2; currNode<=n; ++currNode) /// n-1 fathers
    {
        int currFather;

        in>>currFather;
        sons[currFather].push_back(currNode);
    }

    //for(int i=1; i<=n; ++i) { cout<<i<<" => "; for(list<int>::iterator it = sons[i].begin(); it != sons[i].end(); ++it) cout<<*it<<" "; cout<<"\n"; }
    /// Compute the LMRM path aray aka "Euler Path"
    LMRM_length = 0;
    LMRM_path(1);
    if(pas >= maxPas)
        return -1;

    for(int i=0; i<LMRM_length; ++i)
        if(!first_index[LMRM_values[i]]) /// First index of element 'LMRM_values[i]' hasn't been set yet
            first_index[LMRM_values[i]] = i;
    //for(int i=0; i<LMRM_length; ++i) cout<<LMRM_values[i]<<" "; cout<<"\n";

    /// Compute RMQ table
    array_to_RMQ_matrix(LMRM_values, LMRM_length, rmqArray, NLOG);

    /// Answer the queries
    for(int i=0; i<q; ++i)
    {
        int leftBound, rightBound;
        in>>leftBound>>rightBound;

        int left_index = first_index[leftBound];
        int right_index = first_index[rightBound];

        if(left_index > right_index)
            swap(left_index, right_index);

        //cout<<left_index<<" "<<right_index<<" ";

        out<<queryRMQ(left_index, right_index)<<"\n";
    }

    return 0;
}