Cod sursa(job #886637)

Utilizator toranagahVlad Badelita toranagah Data 23 februarie 2013 02:10:55
Problema Lowest Common Ancestor Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 2.15 kb
#include <algorithm>
#include <fstream>
#include <iostream>
#include <vector>
using namespace std;

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

const int MAX_N = 100100;
const int MAX_M = 2000000;
const int MAX_LOG = 20;

int N, M;
vector<int> tree[MAX_N];
int father[MAX_N];
int euler_position[MAX_N];
int euler_node[2 * MAX_N];
int euler_depth[2 * MAX_N];
int euler_length = 0;
int log2[2 * MAX_N];
int rmq[2 * MAX_N][MAX_LOG];

void cross_euler(int node, int depth);
void euler_crossing(int node, int depth);
void compute_rmq();
int lca(int a, int b);

int main() {
    fin >> N >> M;
    for (int i = 2; i <= N; ++i) {
        fin >> father[i];
        tree[father[i]].push_back(i);
    }
    euler_crossing(1, 0);
    
    compute_rmq();
    int a, b;
    for (int i = 1; i <= M; ++i) {
        fin >> a >> b;
        fout << lca(a, b) << '\n';
    }
    return 0;
}

inline void cross_euler(int node, int depth) {
    ++euler_length;
    rmq[euler_length][0] = euler_length;
    euler_node[euler_length] = node;
    euler_depth[euler_length] = depth;
}

void euler_crossing(int node, int depth) {
    cross_euler(node, depth);
    euler_position[node] = euler_length;
    for (vector<int>::iterator it = tree[node].begin(); it != tree[node].end(); ++it) {
        euler_crossing(*it, depth + 1);
        cross_euler(node, depth);
    }
}

void compute_rmq() {
    for (int l = 1; (1 << l) <= euler_length; ++l) {
        for (int i = 1; i + (1 << l) - 1 <= euler_length; ++i) {
            if (euler_depth[rmq[i][l - 1]] <= euler_depth[rmq[i + (1 << (l - 1))][l - 1]]) {
                rmq[i][l] = rmq[i][l - 1];
            } else {
                rmq[i][l] = rmq[i + (1 << (l - 1))][l - 1];
            }
        }
    }

    log2[1] = 0;
    for (int i = 2; i <= euler_length; ++i) {
        log2[i] = log2[i / 2] + 1;
    }
}

inline int lca(int a, int b) {
    int lo = euler_position[a];
    int hi = euler_position[b];
    if (lo > hi) swap(lo, hi);
    
    int k = log2[hi - lo + 1];
    if (euler_depth[rmq[lo][k]] <= euler_depth[rmq[hi - (1 << k) + 1][k]]) {
        return euler_node[rmq[lo][k]];
    } else {
        return euler_node[rmq[hi - (1 << k) + 1][k]];
    }
}