Cod sursa(job #2001048)

Utilizator savigunFeleaga Dragos-George savigun Data 15 iulie 2017 16:14:11
Problema Lowest Common Ancestor Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 4.19 kb
#include <iostream>
#include <fstream>
#include <vector>
#include <cassert>
using namespace std;


ifstream in("lca.in");
ofstream out("lca.out");

const int MAXN = 1e5 + 5;
int n, m, nop;
int level[MAXN], parent[MAXN], whatPath[MAXN], whatPos[MAXN], size[MAXN], dp[6][MAXN], pathLevel[MAXN], log[MAXN];
vector<int> g[MAXN], paths[MAXN];


const int BUF_SIZE = 1 << 22;

int ptr;
char buffer[BUF_SIZE];

void advance() {
    ++ptr;
    if (ptr == BUF_SIZE) {
        ptr = 0;
        in.read(buffer, BUF_SIZE);
    }
}

int read_int() {
    int nr = 0;
    while (!isdigit(buffer[ptr])) advance();
    while (isdigit(buffer[ptr])) {
        nr = nr * 10 + (buffer[ptr] - '0');
        advance();
    }

    return nr;
}

inline void set_path(int x, int p) {
    whatPath[x] = p;
    whatPos[x] = paths[p].size();
    paths[p].push_back(x);
}

inline int get_path_parent(int x) {
    return paths[whatPath[x]].back();
}

inline int get_path_parent_from_path(int p) {
    if (p == 0) return 0;
    return paths[p].back();
}

void HPD(int x, int depth) {
    level[x] = depth;
    if (g[x].size() == 0) {
        size[x] = 1;
        nop++;
        set_path(x, nop);
    } else {
        int max_size = 0, max_path;
        size[x] = 1;

        for (int i = 0; i < g[x].size(); ++i) {
            int y = g[x][i];
            HPD(y, depth + 1);
            size[x] += size[y];
            if (size[y] > max_size) {
                max_size = size[y];
                max_path = whatPath[y];
            }
        }

        set_path(x, max_path);

        // set path as parent to all children paths
        for (int i = 0; i < g[x].size(); ++i) {
            int y = g[x][i];
            if (whatPath[y] != whatPath[x]) {
                dp[0][whatPath[y]] = whatPath[x];
            }
        }
    }
}

void preprocess() {
    int lg = 0;
    int next = 2;
    for (int i = 1; i <= 33; ++i) {
        if (i == next) {
            lg++;
            next *= 2;
        }
        log[i] = lg;
    }

    for (int k = 1; k <= 3; ++k) {
        for (int path = 1; path <= nop; ++path) {
            dp[k][path] = dp[k-1][dp[k-1][path]];
        }
    }


    /*for (int k = 0; k <= 3; ++k) {
        for (int path = 1; path <= nop; ++path) {
            dp[k][path] = get_path_parent_from_path(dp[k][path]);
        }
    }*/
}

void set_path_level(int x, int p) {
    pathLevel[whatPath[x]] = p;
    for (int i = 0; i < g[x].size(); ++i) {
        int y = g[x][i];
        if (whatPath[y] != whatPath[x]) set_path_level(y, p + 1); else set_path_level(y, p);
    }
}

void levelize(int &x, int &y) {
    int xPath = whatPath[x];
    int yPath = whatPath[y];
    if (pathLevel[xPath] != pathLevel[yPath]) {
        if (pathLevel[xPath] < pathLevel[yPath]) {
            swap(x, y);
            swap(xPath, yPath);
        }

        int bit = log[pathLevel[xPath]];
        for (; bit >= 0; --bit) {
            if (pathLevel[dp[bit][xPath]] > pathLevel[yPath]) {
                xPath = dp[bit][xPath];
            }
        }

        x = parent[get_path_parent_from_path(xPath)];
    }
}

int query(int x, int y) {
    levelize(x, y);

    if (whatPath[x] == whatPath[y]) return (level[x] > level[y]) ? y : x;

    int xPath = whatPath[x];
    int yPath = whatPath[y];

    int bit = log[pathLevel[xPath]];

    for (; bit >= 0; --bit) {
       if (dp[bit][xPath] != dp[bit][yPath]) {
            xPath = dp[bit][xPath];
            yPath = dp[bit][yPath];
       }
    }

    int xPathParent = get_path_parent_from_path(xPath);
    int yPathParent = get_path_parent_from_path(yPath);

    return (level[xPathParent] > level[yPathParent]) ? parent[yPathParent] : parent[xPathParent];
}


int main()
{
    in.read(buffer, BUF_SIZE);
    n = read_int();
    m = read_int();
    for (int i = 2, x; i <= n; ++i) {
        x = read_int();
        parent[i] = x;
        g[x].push_back(i);
    }

    HPD(1, 1);

    preprocess();

    set_path_level(1, 1);

    for (int i = 1, x, y; i <= m; ++i) {
        x = read_int();
        y = read_int();
        out << query(x, y) << "\n";
    }

    return 0;
}