#include <errno.h>
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_STRING_SIZE 256
#define MIN(X, Y) \
({ \
typeof(X) x_ = (X); \
typeof(Y) y_ = (Y); \
(x_ < y_) ? x_ : y_; \
})
#define DIE(assertion, call_description) \
do { \
if (assertion) { \
fprintf(stderr, "(%s, %d): ", __FILE__, __LINE__); \
perror(call_description); \
exit(errno); \
} \
} while (0)
typedef struct ll_node_t {
void *data;
struct ll_node_t *next;
} ll_node_t;
typedef struct linked_list_t {
ll_node_t *head;
unsigned int data_size;
unsigned int size;
} linked_list_t;
typedef struct {
linked_list_t **neighbors;
int data_size;
int nodes;
} graph_t;
typedef struct queue_t queue_t;
struct queue_t {
unsigned int max_size;
unsigned int size;
unsigned int data_size;
unsigned int read_idx;
unsigned int write_idx;
void **buff;
};
typedef struct stack {
struct linked_list_t *list;
} stack;
linked_list_t *ll_create(unsigned int data_size) {
linked_list_t *list = malloc(sizeof(linked_list_t));
list->head = NULL;
list->data_size = data_size;
list->size = 0;
return list;
}
void ll_add_nth_node(linked_list_t *list, int n, const void *new_data) {
if (n >= (int)list->size) n = list->size;
ll_node_t *node = malloc(sizeof(*node));
node->data = malloc(list->data_size);
if (!list->head) {
node->next = NULL;
memcpy(node->data, new_data, list->data_size);
list->head = node;
list->size++;
return;
}
ll_node_t *current = list->head;
for (int i = 0; i < (int)n - 1; i++) current = current->next;
if (n == 0) {
node->next = list->head;
memcpy(node->data, new_data, list->data_size);
list->head = node;
} else {
memcpy(node->data, new_data, list->data_size);
node->next = current->next;
current->next = node;
}
list->size++;
}
ll_node_t *ll_remove_nth_node(linked_list_t *list, unsigned int n) {
if (n >= list->size) n = list->size - 1;
if (!list->head) return NULL;
if (n == 0) {
ll_node_t *temp = list->head;
list->head = temp->next;
list->size--;
return temp;
}
ll_node_t *current = list->head;
for (int i = 0; i < (int)n - 1; i++) current = current->next;
ll_node_t *temp = current->next;
ll_node_t *next = temp->next;
current->next = next;
list->size--;
return temp;
}
unsigned int ll_get_size(linked_list_t *list) { return list->size; }
void ll_free(linked_list_t **pp_list) {
int n = (*pp_list)->size;
ll_node_t *current = (*pp_list)->head;
for (int i = 0; i < n; i++) {
ll_node_t *temp = current->next;
free(current->data);
free(current);
current = temp;
}
free(*pp_list);
}
void ll_print_int(linked_list_t *list) {
ll_node_t *curr;
if (!list) return;
curr = list->head;
while (!curr) {
printf("%d ", *((int *)curr->data));
curr = curr->next;
}
printf("\n");
}
void ll_print_string(linked_list_t *list) {
ll_node_t *curr;
if (!list) return;
curr = list->head;
while (!curr) {
printf("%s ", (char *)curr->data);
curr = curr->next;
}
printf("\n");
}
graph_t *lg_create(int nodes) {
graph_t *graph = malloc(sizeof(graph_t));
graph->nodes = nodes;
graph->neighbors = malloc(nodes * sizeof(linked_list_t *));
for (int i = 0; i < nodes; i++) graph->neighbors[i] = ll_create(sizeof(int));
return graph;
}
void lg_add_edge(graph_t *graph, int src, int dest) {
ll_add_nth_node(graph->neighbors[src], graph->neighbors[src]->size, &dest);
}
int lg_has_edge(graph_t *graph, int src, int dest) {
ll_node_t *current = graph->neighbors[src]->head;
while (current) {
int *data = current->data;
if (*data == dest) return 1;
current = current->next;
}
return 0;
}
void lg_remove_edge(graph_t *graph, int src, int dest) {
ll_node_t *current = graph->neighbors[src]->head;
int index = 0;
while (current) {
int *data = current->data;
if (*data == dest) {
ll_node_t *node = ll_remove_nth_node(graph->neighbors[src], index);
free(node->data);
free(node);
return;
}
index++;
current = current->next;
}
}
void lg_free(graph_t *graph) {
for (int i = 0; i < graph->nodes; i++) ll_free(&graph->neighbors[i]);
free(graph->neighbors);
}
stack *st_create(unsigned int data_size) {
stack *st = malloc(sizeof(stack));
st->list = ll_create(data_size);
return st;
}
unsigned int st_get_size(stack *st) {
if (!st || !st->list) return 0;
return st->list->size;
}
unsigned int st_is_empty(stack *stack) {
if (!stack->list || !stack->list->size) return 1;
return 0;
}
void *st_peek(stack *st) {
if (!st || !st->list || !st->list->size) return NULL;
return st->list->head->data;
}
ll_node_t *st_pop(stack *st) {
if (!st || !st->list) return NULL;
ll_node_t *node;
node = ll_remove_nth_node(st->list, 0);
return node;
}
void st_push(stack *stack, void *new_data) {
if (!stack->list) return;
ll_add_nth_node(stack->list, 0, new_data);
}
void st_clear(stack *st) {
if (!st || !st->list) return;
ll_free(&st->list);
}
void st_free(stack *st) {
if (!st || !st->list) return;
ll_free(&st->list);
free(st);
}
typedef struct node_data {
int node;
int depth;
} node_data;
int euler_generate(graph_t *graph, node_data *euler) {
int euler_size = 0;
stack *st = st_create(sizeof(node_data **));
node_data *first = malloc(sizeof(*first));
first->node = 1;
first->depth = 0;
int *viz = calloc(graph->nodes, sizeof(int));
st_push(st, &first);
while (!st_is_empty(st)) {
node_data *current = *(node_data **)st_peek(st);
int node = current->node;
// fprintf(stderr, "euler size:, %d\n", euler_size);
euler[euler_size].node = node;
euler[euler_size].depth = current->depth;
euler_size++;
viz[node] = 1;
int has_neighbours = 0;
// fprintf(stderr, "nodul, %d\n", node);
ll_node_t *curr = graph->neighbors[node]->head;
while (curr) {
int *data = curr->data;
// fprintf(stderr, "vecinul, %d\n", *data);
if (!viz[*data]) {
viz[*data] = 1;
has_neighbours = 1;
node_data *new = malloc(sizeof(*new));
new->node = *data;
new->depth = current->depth + 1;
st_push(st, &new);
break;
}
curr = curr->next;
}
if (!has_neighbours) {
node_data **old = (node_data **)st_pop(st);
free(*old);
free(old);
}
}
return euler_size;
}
int logtwo(int n) {
if (n == 0) return 0;
int cpn = n;
int ans = 0;
while (n) {
n = n >> 1;
ans++;
}
// if ((1 << ans) == cpn) return ans;
return ans - 1;
}
int main(void) {
int n, m;
FILE *in = fopen("lca.in", "r");
FILE *out = fopen("lca.out", "w");
fscanf(in, "%d %d", &n, &m);
graph_t *tree = lg_create(n + 1);
for (int i = 1; i < n; i++) {
int son;
fscanf(in, "%d", &son);
lg_add_edge(tree, son, i + 1);
lg_add_edge(tree, i + 1, son);
}
node_data *euler = calloc(10 * tree->nodes, sizeof(node_data));
int euler_size = euler_generate(tree, euler);
int rmq_size = log2(euler_size);
// for (int i = 0; i < euler_size; i++) printf("%d ", euler[i].node);
// printf("\n");
// for (int i = 0; i < euler_size; i++) printf("%d ", euler[i].depth);
int **rmq = calloc(euler_size, sizeof(int *));
for (int i = 0; i < euler_size; i++) {
rmq[i] = calloc(rmq_size, sizeof(int));
}
for (int i = 0; i < euler_size; i++) {
rmq[i][0] = i;
}
for (int j = 1; (1 << j) <= euler_size; j++) {
for (int i = 0; i + (1 << j) - 1 < euler_size; i++) {
if (euler[rmq[i][j - 1]].depth <=
euler[rmq[i + (1 << (j - 1))][j - 1]].depth)
rmq[i][j] = rmq[i][j - 1];
else
rmq[i][j] = rmq[i + (1 << (j - 1))][j - 1];
}
}
int *first_position = calloc(n + 1, sizeof(int));
for (int i = 0; i < euler_size; i++) {
if (!first_position[euler[i].node]) {
first_position[euler[i].node] = i;
}
}
for (int i = 0; i < m; i++) {
int x, y;
fscanf(in, "%d %d", &x, &y);
if (x == y) {
fprintf(out, "%d\n", x);
continue;
}
x = first_position[x];
y = first_position[y];
if (x > y) {
int aux = x;
x = y;
y = aux;
}
int k = floor(log2(y - x + 1));
int ans;
if (euler[rmq[x][k]].depth <= euler[rmq[y - (1 << k) + 1][k]].depth)
ans = euler[rmq[x][k]].node;
else
ans = euler[rmq[y - (1 << k) + 1][k]].node;
fprintf(out, "%d\n", ans);
}
free(euler);
for (int i = 0; i < euler_size; i++) free(rmq[i]);
free(rmq);
free(first_position);
lg_free(tree);
fclose(in);
fclose(out);
return 0;
}