Cod sursa(job #673679)

Utilizator ukiandreaAndreea Lucau ukiandrea Data 4 februarie 2012 19:42:16
Problema Lowest Common Ancestor Scor 70
Compilator cpp Status done
Runda Arhiva educationala Marime 2.91 kb
#include <stdio.h>
#include <stdlib.h>

#include <queue>

int a[1000000];
int mins[1000000];
int dfs_size;

struct node {
	int value;
	struct node *next;
};

struct list {
	node *head;
};

list* create_list()
{
	list *l = (list*)calloc(1, sizeof(list));
	l->head = NULL;
	return l;
}

void insert_list(list* l, int value, int weight)
{
	if (l->head == NULL) {
		l->head = (node*)calloc(1, sizeof(node));
		l->head->value = value;
		return;
	}

	node *p = l->head;
	while (p->next != NULL)
		p = p->next;

	node *n = (node*)calloc(1, sizeof(node));
	n->value = value;
	p->next = n;
}

void destroy_list(list **l)
{
	while ((*l)->head != NULL) {
		node *p = (*l)->head;
		(*l)->head = (*l)->head->next;
		
		free(p);
	}
}

enum colors {
	WHITE = 0,
	GRAY,
	BLACK
};

struct tree {
	int n;
	list **adj;
	int *positions;
};

tree* create_tree(int size)
{
	tree *t = (tree*)calloc(1, sizeof(tree));
	t->n = size;
	t->adj = (list**)calloc(size, sizeof(list*));
	t->positions = (int*)calloc(size, sizeof(int));

	for (int i = 0; i < size; i++)
		t->positions[i] = -1;
	return t;
}

void add_tree_edge(tree *t, int v1, int v2, int w)
{
	if (t->adj[v1] == NULL) 
		t->adj[v1] = create_list();

	insert_list(t->adj[v1], v2, w);
}

void destroy_tree(tree **t)
{
	for (int i = 0; i < (*t)->n; i++) {
		if ((*t)->adj[i])
			destroy_list(&((*t)->adj[i]));
	}

	free((*t)->adj);
	free((*t)->positions);
	free(*t);
}

void dfs(tree *t, int source)
{
	if (t->positions[source] == -1)
		t->positions[source] = dfs_size;
	a[dfs_size++] = source;

	node *n = NULL;
	if (t->adj[source]) {
		n = t->adj[source]->head;
		while (n) {
			dfs(t, n->value);
			a[dfs_size++] = source;

			n = n->next;
		}
	}
}

void initialize(int node, int b, int e)
{
	if (b == e)
		mins[node] = b;
	else {
		initialize(2 * node, b, (b + e) / 2);
		initialize(2 * node + 1, (b + e) / 2 + 1, e);

		mins[node] = (a[mins[2 * node]] < a[mins[2 * node + 1]]) ? mins[2 * node] : mins[2 * node + 1];
	}
}

int query(int node, int b, int e, int i, int j)
{
	if (e < i || j < b)
		return -1;

	if (i <= b && e <= j)
		return mins[node];

	int p1 = query(2 * node, b, (b + e) / 2, i, j);
	int p2 = query(2 * node + 1, (b + e) / 2 + 1, e, i, j);

	if (p1 == -1)
		return p2;

	if (p2 == -1)
		return p1;

	return (a[p1] < a[p2]) ? p1 : p2;
}

int main()
{
	int n, m;
	tree *t = NULL;

	freopen("lca.in", "r", stdin);
	freopen("lca.out", "w", stdout);

	scanf("%d %d\n", &n, &m);
	t = create_tree(n);

	for (int i = 0; i < (n - 1); i++) {
		int parent;
		scanf("%d ", &parent);
		
		add_tree_edge(t, parent - 1, i + 1, 0);
	}

	dfs_size = 0;
	dfs(t, 0);
	initialize(1, 0, dfs_size - 1);

	for (int i = 0; i < m; i++) {
		int u, v;
		scanf("%d %d\n", &u, &v);

		int p1 = t->positions[u - 1];
		int p2 = t->positions[v - 1];
		int q = -1;
		if (p1 < p2)
			q = query(1, 0, dfs_size - 1, p1, p2);
		else
			q = query(1, 0, dfs_size - 1, p2, p1);
		printf("%d\n", a[q] + 1);
	}

	destroy_tree(&t);

	return 0;
}