Cod sursa(job #2498853)

Utilizator mitapirvuetAndrei Iachim mitapirvuet Data 24 noiembrie 2019 17:07:02
Problema Lowest Common Ancestor Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.26 kb
#include <bits/stdc++.h>

#define N 100000
#define LMAX 100 // computed as ceil(log(N))
  
void eulerTour(const std::vector<std::vector<int>>& graph, int currentNode, std::vector<bool>& visited,
               std::vector<int>& tour, std::vector<int>& depth, std::vector<int>& firstOccurence,  int level) {
    visited[currentNode] = true;
    depth[currentNode] = level;

    if(firstOccurence[currentNode] == -1) {
        firstOccurence[currentNode] = tour.size();
    }

    tour.push_back(currentNode);

    for(int i = 0; i < graph[currentNode].size(); ++i) {
        if(!visited[graph[currentNode][i]]) {
            eulerTour(graph, graph[currentNode][i], visited, tour, depth, firstOccurence, level + 1);
            tour.push_back(currentNode);
        }
    }
}

std::vector<int> lca(const std::vector<std::vector<int>>& graph, const std::vector< std::pair<int, int> >& queries) { 
    std::vector<bool> visited(graph.size(), false);
    std::vector<int> euler(1,0), depth(graph.size()), firstOcurrence(graph.size(), -1), eulerLevels;
    std::vector<int> res;
    
    eulerTour(graph, 1, visited, euler, depth, firstOcurrence, 1);

    for(auto r : euler) {
        eulerLevels.push_back(depth[r]);
    }

    std::vector<std::vector<int>> rmq(LMAX);

    for(auto& v:rmq) {
        v.resize(eulerLevels.size() + 1);
    }

    std::vector<int> lg(eulerLevels.size() + 1, 0);

    int n = eulerLevels.size();

	for (int i = 2; i <= n; i++) {
		lg[i] = lg[i/2] + 1;
    }
 
	for (int i = 1; i <= n; i++) {
		rmq[0][i] = i;
    }
 
	for (int i = 1; (1 << i) < n; i++) {
        for (int j=1; j <= n - (1 << i); j++) {
            int l = 1 << (i-1);
            
            if(eulerLevels[rmq[i-1][j]] < eulerLevels[rmq[i-1][j+l]]) {
                rmq[i][j] = rmq[i-1][j];
            } else {
                rmq[i][j] = rmq[i-1][j+l];
            }
		}
    }
		
    for(auto& query: queries) {
        int firstNode = firstOcurrence[query.first], secondNode = firstOcurrence[query.second];

        if(firstNode > secondNode ) {
            std::swap(firstNode, secondNode);
        }

        int diff = secondNode - firstNode + 1;
        int level = lg[diff];
        int sh = diff - (1 << level);

        if(eulerLevels[rmq[level][firstNode]] < eulerLevels[rmq[level][firstNode+sh]]) {
            res.push_back(euler[rmq[level][firstNode]]);
        } else {
            res.push_back(euler[rmq[level][firstNode+sh]]);
        }
    }

    return res;
}

void addEdge(int a,int b, std::vector<std::vector<int>>& graph) 
{ 
    graph[a].push_back(b); 
    graph[b].push_back(a); 
} 

int main() 
{       
    std::ifstream inputStream;
    std::ofstream outputStream;

    int n, m;
    
    inputStream.open("lca.in");

    inputStream>>n>>m;

    std::vector<std::vector<int>> graph(n + 5);
    std::vector< std::pair<int, int> > queries;
    int src, dest;

    for(int i = 1; i < n ; ++i) {
        inputStream>>dest;

        addEdge(dest, i +1, graph);
    }

    int u , v;

    for(int i = 0; i < m; ++i) {
        inputStream>>u>>v;
        queries.push_back(std::make_pair(u, v));
    }

    std::vector<int> res = lca(graph, queries);

    outputStream.open("lca.out");

    for(auto& r:res) {
        outputStream<<r<<'\n';
    }

    outputStream.close();
    inputStream.close();
    

    return 0; 
}