Cod sursa(job #3233594)

Utilizator rares_ciocieaRares Andrei Ciociea rares_ciociea Data 3 iunie 2024 23:00:12
Problema Lowest Common Ancestor Scor 100
Compilator c-64 Status done
Runda Arhiva educationala Marime 8.55 kb
#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);

  int **rmq = calloc(euler_size + 1, sizeof(int *));

  for (int i = 0; i < euler_size; i++) {
    rmq[i] = calloc(rmq_size + 2, 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);
  free(rmq);
  free(first_position);
  lg_free(tree);

  fclose(in);
  fclose(out);
  return 0;
}