Cod sursa(job #2266186)

Utilizator andreiiiiPopa Andrei andreiiii Data 22 octombrie 2018 14:10:32
Problema Lowest Common Ancestor Scor 0
Compilator c-64 Status done
Runda Arhiva educationala Marime 2.74 kb
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define NMAX 100005

typedef struct {
    int *first, *next, *to;
    int edges;
} Graph;

int lsb(int x) {
    return x ^ (x & (x - 1));
}

int msb(int x) {
    int v = x;
    v |= x >> 1;
    v |= v >> 2;
    v |= v >> 4;
    v |= v >> 8;
    v |= v >> 16;
    return (v + 1) >> 1;
}

int parent[NMAX];
int preorder[NMAX], asc[NMAX], level[NMAX], inlabel[NMAX], head[NMAX];
Graph g;

void new_graph(Graph* g, int n, int m) {
    g->first = (int*) malloc(sizeof(int) * (n + 1));
    memset(g->first, -1, sizeof(int) * (n + 1));
    g->next = (int*) malloc(sizeof(int) * m);
    g->to = (int*) malloc(sizeof(int) * m);
    g->edges = 0;
}

void add_edge(Graph* g, int from, int to) {
    g->to[g->edges] = to;
    g->next[g->edges] = g->first[from];
    g->first[from] = g->edges++;
}

void delete_graph(Graph* g) {
    free(g->first);
    free(g->next);
    free(g->to);
}

int dfs1(int node, int pos) {
    preorder[node] = ++pos;
    inlabel[node] = preorder[node];
    for (int e = g.first[node]; e != -1; e = g.next[e]) {
        int to = g.to[e];
        level[to] = level[node] + 1;
        pos = dfs1(to, pos);
        if (lsb(inlabel[to]) > lsb(inlabel[node])) {
            inlabel[node] = inlabel[to];
        }
    }
    head[inlabel[node]] = node;
    return pos;
}

void dfs2(int node) {
    if (parent[node] != -1) {
        asc[node] = asc[parent[node]];
        if (inlabel[node] != inlabel[parent[node]]) {
            asc[node] |= lsb(inlabel[node]);
        }
    } else {
        asc[node] = lsb(inlabel[node]);
    }
    for (int e = g.first[node]; e != -1; e = g.next[e]) {
        int to = g.to[e];
        dfs2(to);
    }
}

void preprocess(int n) {
    int i;
    parent[1] = -1;
    level[1] = 0;
    dfs1(1, 0);
    dfs2(1);
}

 int findAnc(int x, int i, int b, int j, int lz) {
    if (inlabel[x] == lz) {
        return x;
    }
    int k = msb(asc[x] & (j - 1));
    return parent[head[(inlabel[x] & ~(k - 1)) | k]];
}

 int lca(int x, int y) {
    int i = msb(inlabel[x] ^ inlabel[y]);
    int b = (inlabel[x] | inlabel[y]) & ~(i - 1);
    int j = lsb(asc[x] & asc[y] & ~(i - 1));
    int lz = (inlabel[x] & ~(j - 1)) | j;
    
    int x1 = findAnc(x, i, b, j, lz);
    int y1 = findAnc(y, i, b, j, lz);
    return level[x1] < level[y1] ? x1: y1;
}

int main() {
    freopen("lca.in", "r", stdin);
    freopen("lca.out", "w", stdout);
    int n, q, i;
    scanf("%d%d", &n, &q);

    new_graph(&g, n, n - 1);
    for (i = 2; i <= n; ++i) {
        int f;
        scanf("%d", &f);
        parent[i] = f;
        add_edge(&g, f, i);
    }

    preprocess(n);

    while (q-- > 0) {
        int x, y;
        scanf("%d%d", &x, &y);

        printf("%d\n", lca(x, y));
    }

    delete_graph(&g);
    
    return 0;
}