Cod sursa(job #1210508)

Utilizator dm1sevenDan Marius dm1seven Data 20 iulie 2014 11:03:42
Problema Lowest Common Ancestor Scor 70
Compilator cpp Status done
Runda Arhiva educationala Marime 3.46 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;
		}
	}

	void build_rmq_data(int N, int* v, vector<vector<int>>& ids_min)
	{
		ids_min.resize(N + 1);
		for (int i = 1; i < N; i++)  {
			ids_min[i].resize((int)log2(N - i) + 1);
			ids_min[i][0] = v[i] <= v[i + 1] ? i : i + 1;
		}

		int logN = (int) log2(N);
		for (int k = 1; k <= logN; k++)	{			
			int km1 = k - 1, two_km1 = (1 << km1), two_k = two_km1 << 1;
			for (int i = 1; i <= N - two_k; i++) {
				int id_min1 = ids_min[i][km1]; 
				int id_min2 = ids_min[i + two_km1][km1];
				ids_min[i][k] = v[id_min1] <= v[id_min2] ? id_min1 : id_min2;
			}
		}
	}

	int rmq(int x, int y, int* v, vector<vector<int>>& ids_min)
	{
		if (x == y) return x;
		
		int k = (int)log2(y - x);
		int id_min1 = ids_min[x][k];
		int id_min2 = ids_min[y - (1 << k)][k];

		return v[id_min1] <= v[id_min2] ? id_min1 : id_min2;
	}

	int lca(int u, int v, int* er, int* depths_er, vector<vector<int>>& er_pos, vector<vector<int>>& ids_min)
	{
		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 first 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];
		
		//range minimum query for minimum

		int id_min = rmq(pos_u, pos_v, depths_er, ids_min);

		return er[id_min];

		////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 + 1];
	int* depths_er = new int[no_ch + N + 1];

	vector<vector<int>> er_pos;
	er_pos.resize(N + 1);

	int eid = 1;
	dfs_euler_depth(1, 0, N, tree, eid, er, er_pos, depths);
	for (int i = 1; i <= no_ch + N; i++) depths_er[i] = depths[er[i]];

	vector<vector<int>> ids_min;
	build_rmq_data(no_ch + N, depths_er, ids_min);
	
	for (int i = 1; i <= M; i++) {
		int u, v;
		ifs >> u >> v;
		ofs << lca(u, v, er, depths_er, er_pos, ids_min) << "\n";
	}

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

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

	return 0;
}