Cod sursa(job #1572237)

Utilizator stoianmihailStoian Mihail stoianmihail Data 18 ianuarie 2016 20:14:55
Problema Lowest Common Ancestor Scor 100
Compilator c Status done
Runda Arhiva educationala Marime 2.31 kb
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#define Nadejde 100000
#define MAX_LOG 16

typedef struct {
  int v, next;
} list;

int N, Q, lim;
int d[Nadejde + 1];
int lg[Nadejde + 2];                  // lg[i] este log2(i).
list l[Nadejde + 1];                  // lista arcelor din arbore.
int adj[Nadejde + 1];                 // capetele listelor de adiacenta.
int father[MAX_LOG + 1][Nadejde + 1]; // father[i][u] este al 2 ^ i - lea tata al nodului "u".

/** Adauga-l pe "v" la lista de adiacenta a nodului "u". **/
void addEdge(int u, int v, int pos) {
  l[pos].v = v;
  l[pos].next = adj[u];
  adj[u] = pos;
}

/** Exploreaza graful, calculand adancimea fiecarui nod. **/
void dfs(int u, int dad) {
  int pos;
  if (!d[u]) {
    d[u] = d[dad] + 1;
    for (pos = adj[u]; pos; pos = l[pos].next) {
      dfs(l[pos].v, u);
    }
  }
}

/** Precalculeaza "lg". **/
void log() {
  int i;

  for (i = 0; i <= MAX_LOG; i++) {
    lg[1 << i] = i;
  }
  for (i = 3; i <= lim; i++) {
    if (!lg[i]) {
      lg[i] = lg[i - 1];
    }
  }
}

/** Urca nodul "u" cu "level" nivele. **/
void climb(int *u, int level) {
  for (; level; level &= level - 1) {
    (*u) = father[lg[level & -level]][*u];
  }
}

int main(void) {
  int u, v, i, diff, result;
  FILE *f = fopen("lca.in", "r");

  /* Citirea datelor. */
  fscanf(f, "%d %d", &N, &Q);
  for (lim = N + 1, u = 2; u <= N; u++) {
    fscanf(f, "%d", &father[0][u]);
    addEdge(father[0][u], u, u - 1);
  }

  /* Calcularea solutiei. */
  dfs(1, 0);
  log();

  /* Precalcularea parintilor. */
  for (i = 1; i <= lg[lim]; i++) {
    for (u = 1; u <= N; u++) {
      father[i][u] = father[i - 1][father[i - 1][u]];
    }
  }

  /* Raspunde la intrebari. */
  freopen("lca.out", "w", stdout);
  while (Q--) {
    fscanf(f, "%d %d", &u, &v);

    /* Vedem pe cine urcam mai sus in arbore. */
    diff = d[u] - d[v];
    if (diff < 0) {
      climb(&v, -diff);
    } else {
      climb(&u, diff);
    }

    /* Calcularea lca-ului. */
    if (u == v) {
      result = u;
    } else {
      for (i = lg[d[u]]; i >= 0; i--) {
        if (father[i][u] != father[i][v]) {
         u = father[i][u];
         v = father[i][v];
        }
      }
      result = father[0][u];
    }
    fprintf(stdout, "%d\n", result);
  }
  fclose(f);
  fclose(stdout);

  /// Multumim Doamne!
  puts("Doamne ajuta!");
  return 0;
}