Cod sursa(job #1210150)

Utilizator dm1sevenDan Marius dm1seven Data 19 iulie 2014 13:00:32
Problema Lowest Common Ancestor Scor 30
Compilator cpp Status done
Runda Arhiva educationala Marime 3.01 kb
#include <iostream>
using namespace std;
#include <fstream>
#include <algorithm>
#include <list>
#include <vector>

namespace e_040_lca_
{
	void build_tree(int N, int* parents, vector<list<int>>& tree)
	{
		tree.resize(N + 1);

		//create the tree
		for (int i = 2; i <= N; i++) {
			int p = parents[i];
			tree[p].push_back(i); //add the child
		}
	}

	void dfs_euler_depth(int node, int depth, int N, vector<list<int>>& tree, int& eid, int* er, vector<vector<int>>& er_pos, int* depths)
	{
		depths[node] = depth;
		er_pos[node].push_back(eid);
		er[eid++] = node;
		for (auto& child : tree[node]) {
			dfs_euler_depth(child, depth + 1, N, tree, eid, er, er_pos, depths);
			er_pos[node].push_back(eid);
			er[eid++] = node;
		}
	}

	int lca_search(int u, int v, vector<list<int>>& tree, int* er, int* depths)
	{
		if (u == v) return u;
		
		//look for u and v in the euler representation
		int f = -1;
		int idf = 0, ids = 0;
		int i = 0;
		while (1) {
			if (er[i] == u) {
				if (f == v) { ids = i; break; }
				else {
					f = u; idf = i;
				}
			}

			if (er[i] == v) {
				if (f == u) { ids = i;  break; }
				else {
					f = v; idf = i;
				}
			}

			i++;
		}

		//int the range idf and ids find the node with the minimum depth
		int id_min = idf;
		for (int i = idf + 1; i <= ids; i++) {
			if (depths[er[i]] < depths[er[id_min]]) id_min = i;
		}

		//return the lca of the nodes u and v
		return er[id_min];
	}

	int lca(int u, int v, vector<list<int>>& tree, int* er, vector<vector<int>>& er_pos, int* depths)
	{
		if (u == v) return u;

		//who appears first and who second
		if (er_pos[u].front() > er_pos[v].front()) swap(u, v); //ensure u is the firs and v the second

		int pos_v = er_pos[v].front();

		unsigned int i = 1;
		while (i < er_pos[u].size() && er_pos[u][i] < pos_v) i++;
		
		int pos_u = er_pos[u][i - 1];
		
		//int the range idf and ids find the node with the minimum depth
		int id_min = pos_u;
		for (int i = pos_u + 1; i <= pos_v; i++) {
			if (depths[er[i]] < depths[er[id_min]]) id_min = i;
		}

		//return the lca of the nodes u and v
		return er[id_min];
	}
}
	
//int e_040_lca()
int main()
{
	using namespace e_040_lca_;

	int N, M;

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

	ifs >> N >> M;
	int* parents = new int[N + 1];
	int* depths = new int[N + 1];

	for (int i = 2; i <= N; i++) {
		int p;
		ifs >> p;
		parents[i] = p;
	}

	vector<list<int>> tree;
	build_tree(N, parents, tree);

	//count the number of childs
	int no_ch = 0;
	for (int i = 1; i <= N; i++) {
		no_ch += tree[i].size();
	}

	//euler representation
	int* er = new int[no_ch + N];
	vector<vector<int>> er_pos;
	er_pos.resize(N + 1);

	int eid = 0;
	dfs_euler_depth(1, 0, N, tree, eid, er, er_pos, depths);
	
	for (int i = 1; i <= M; i++) {
		int u, v;
		ifs >> u >> v;
		ofs << lca(u, v, tree, er, er_pos, depths) << "\n";
	}

	ifs.close();
	ofs.close();

	delete[] parents; delete[] depths; delete[] er;

	return 0;
}