Cod sursa(job #2500468)

Utilizator mihnea00Duican Mihnea mihnea00 Data 28 noiembrie 2019 00:00:10
Problema Lowest Common Ancestor Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.32 kb
#include <iostream>
#include <fstream>
#include <vector>

void mySwap (int &a, int &b) {
	a = a ^ b;
	b = a ^ b;
	a = a ^ b;
}

void recursiveDfs (int &node, int &level, std::vector<int> &eulerRep,
	std::vector<int> &levelEvidence, int *firstOccourance,
	std::vector<std::vector<int>> &graph, int &fromNode) {

	eulerRep.push_back(node);
	levelEvidence.push_back(level);
	firstOccourance[node] = eulerRep.size() - 1;

	for (int i = 0; i < graph[node].size(); ++i) {
		if (graph[node][i] == fromNode)
			continue;

		int nextLevel = level + 1;
		recursiveDfs(graph[node][i], nextLevel, eulerRep, levelEvidence,
			firstOccourance, graph, node);

		eulerRep.push_back(node);
		levelEvidence.push_back(level);
	}
}

void makeRmq(int **rmq, const int &sizeOfRmq, std::vector<int> &levelEvidence, int *lg) {
	int lgIdx;

	for (int i = 2; i <= sizeOfRmq; ++i) {
		lg[i] = lg[i >> 1] + 1;
	}
	for (int i = 1; i <= sizeOfRmq; ++i) {
		rmq[0][i] = i;
	}

	for (int i = 1; (1 << i) < sizeOfRmq; ++i) {
		for (int j = 1; j <= sizeOfRmq - (1 << i); ++j) {
			lgIdx = 1 << (i - 1);
			rmq[i][j] = rmq[i - 1][j];
			if (levelEvidence[rmq[i][j] - 1] > levelEvidence[rmq[i - 1][j + lgIdx] - 1]) {
				rmq[i][j] = rmq[i - 1][j + lgIdx];
			}
		}
	}
}

int getLca(int &node1, int &node2, int *firstOccourance, int *lg,
	std::vector<int> &eulerRep, std::vector<int> &levelEvidence, int **rmq) {

	int oc1 = firstOccourance[node1];
	int oc2 = firstOccourance[node2];

	if (oc1 > oc2)
		mySwap(oc1, oc2);

	int dif = oc2 - oc1 + 1;
	int lgIdx = lg[dif];
	int sol = rmq[lgIdx][oc1 + 1];
	int shift = dif - (1 << lgIdx);

	if (levelEvidence[sol - 1] > levelEvidence[rmq[lgIdx][oc1 + shift + 1] - 1])
		sol = rmq[lgIdx][oc1 + shift + 1];

	return eulerRep[sol - 1];
}

std::vector<int> lca(std::vector<std::vector<int>> &graph,
	std::vector< std::pair<int, int> > &queries) {

	std::vector<int> eulerRep, levelEvidence, ans;
	int *firstOccourance;
	int node = 1, level = 0, **rmq, *lg;

	firstOccourance = new int [graph.size()];
	rmq = new int* [24];
	for (int i = 0; i < 24; ++i) {
		rmq[i] = new int [200005] {0};
	}

	recursiveDfs(node, level, eulerRep, levelEvidence, firstOccourance, graph, level);

	lg = new int [eulerRep.size() + 1] {0};

	makeRmq(rmq, eulerRep.size(), levelEvidence, lg);

	for (int i = 0; i < queries.size(); ++i) {
		ans.push_back(getLca(queries[i].first, queries[i].second,
			firstOccourance, lg, eulerRep, levelEvidence, rmq));
	}

	// for (int i = 0; i < eulerRep.size(); ++i) {
	// 	std::cout << eulerRep[i] << "\n";
	// }

	delete [] firstOccourance;
	for (int i = 0; i < 24; ++i) {
		delete [] rmq[i];
	}
	delete [] lg;
	delete [] rmq;

	return ans;

}

int main () {
	std::ifstream fin("lca.in");
	std::ofstream fout("lca.out");

	int n, m, node1, node2;
	std::vector< std::vector<int> > graph;
	std::vector< std::pair<int, int> > queries;


	fin >> n >> m; // number of nodes and queries
	graph.resize(n + 1);

	for (int i = 2; i <= n; ++i) {
        fin >> node1;
        graph[node1].push_back(i);
        graph[i].push_back(node1);

		// fin >> node1 >> node2;
  //       graph[node1].push_back(node2);
  //       graph[node2].push_back(node1);
	}

	for (int i = 0; i < m; ++i) {
        fin >> node1 >> node2;
		queries.push_back({node1, node2});
	}

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

	for (int i = 0; i < ans.size(); ++i) {
		fout << ans[i] << "\n";
	}

	return 0;
}