Cod sursa(job #2284800)

Utilizator cosmin.pascaruPascaru Cosmin cosmin.pascaru Data 17 noiembrie 2018 16:32:15
Problema Lowest Common Ancestor Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.25 kb
	#include <stdio.h>
	#include <iostream>
	#include <fstream>
	#include <vector>
	#include <array>
	#include <algorithm>
	#include <vector>
	#include <stack>
	#include <set>
	#include <assert.h>
	#include <queue>
	#include <chrono>
	#include <memory>
	#include <cstring>
	 
	using LL = long long;
	using ULL = int long long;
	 
	const std::string _problemName = "lca";
	 
	// #define USE_FILES
	 
	#ifdef USE_FILES
	 
	namespace std {
	std::ifstream fin(_problemName + ".in");
	std::ofstream fout(_problemName + ".out");
	}
	 
	#define cin fin
	#define cout fout
	#endif
	 
	int n, m;
	std::vector< std::vector<int> > ancestors;
	std::vector<int> depths;

	int computeLevel(int node) {
		// TODO: might throw stack overflow?
		
		if (depths[node] == -1) {
			depths[node] = computeLevel(ancestors[0][node]) + 1;
		}
		
		return depths[node];
	}

	void computeDepths() {
		depths.resize(n);
		std::fill(depths.begin(), depths.end(), -1);
		
		depths[0] = 1;
		for (int node = 1; node < n; ++node) {
			depths[node] = computeLevel(node);
		}
	}

	int getAncestor(int heightExp, int node) {
		if (node == -1) {
			return -1;
		}
		return ancestors[heightExp][node];
	}

	void buildAncestors() {
		bool done = false;
		
		for (int heightExp = 1; !done; ++heightExp) {
			ancestors.push_back(std::vector<int>(n));
		
			done = true;
			
			for (int node = 0; node < n; ++node) {
				int firstAncestor  = getAncestor(heightExp - 1, node);
				int secondAncestor = getAncestor(heightExp - 1, firstAncestor);

				if (secondAncestor != -1) {
					done = false;
				}
			
				ancestors[heightExp][node] = secondAncestor;
			}
		}
	}

	int getDepth(int node) {
		if (node == -1) {
			return 0;
		}
		return depths[node];
	}

	void raise(int& node, int levelsCount) {
		for (int i = 0; (1 << i) <= levelsCount; ++i) {
			if (levelsCount & (1 << i)) {
				node = getAncestor(i, node);
			}
		}
	}

	int lca(int node1, int node2) {
		
		// assure node1 is the lower one (depths[node1] >= depths[node2])
		if (depths[node1] < depths[node2]) {
			std::swap(node1, node2);
		}
		
		// raise node1 to the same depth as node2
		int depthDif = depths[node1] - depths[node2];
		raise(node1, depthDif);
		
		// node1 and node2 are now on the same level
		if (node1 == node2) {
			return node1;
		}
		
		// raise them together and find the common ancestor
		int e = 0;
		while (getAncestor(e, node1) != getAncestor(e, node2)) {
			++e;
		}
		
		for (e = e - 1; e >= 0; --e) {
			if (getAncestor(e, node1) != getAncestor(e, node2)) {
				node1 = getAncestor(e, node1);
				node2 = getAncestor(e, node2);
			}
		}
		// assert getAncestor(0, node1) != -1
		// assert getAncestor(0, node1) == getAncestor(0, node2)
		return getAncestor(0, node1);
	}

	int main() {
		std::cin >> n >> m;
		
		ancestors.push_back(std::vector<int>(n));
		ancestors[0][0] = -1;
		
		for (int i = 1; i < n; ++i) {
			std::cin >> ancestors[0][i];
			--ancestors[0][i];
		}
		
		computeDepths();
		buildAncestors();
		
		for (int queryIdx = 0; queryIdx < m; ++queryIdx) {
			int node1, node2;
			std::cin >> node1 >> node2;
			
			--node1;
			--node2;
			
			std::cout << lca(node1, node2) + 1 << '\n';
		}
		return 0;
	}