Cod sursa(job #2680091)

Utilizator ionutpop118Pop Ioan Cristian ionutpop118 Data 2 decembrie 2020 17:12:32
Problema Lowest Common Ancestor Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.21 kb
#include <cstdio>
#include <vector>

using namespace std;

/// Depth-first search of the tree
void dfs(int node, int current_level, vector< vector<int> > &children,
         vector <int> &euler, vector <int> &level, vector<int> &first) {
    euler.push_back(node);
    level.push_back(current_level);
    first[node] = euler.size() - 1; // current tour length

    for (unsigned int i = 0; i < children[node].size(); ++i)
    {
        dfs(children[node][i], current_level + 1, children, euler, level, first);
        euler.push_back(node);
        level.push_back(current_level);
    }
}
/// Generates the Euler tour
void generate_euler_tour(vector <vector<int> > &children,
                         vector <int> &euler, vector <int> &level, vector<int> &first) {
    dfs(1, 0, children, euler, level, first); // node 1 is root in this scenario
}

/// Builds the rmq
void build_rmq(vector < vector<int> > &rmq, vector <int> &lg,
               int &tour_length, vector <int> &level) {
    for (int i = 1; i <= tour_length; ++i) {
        rmq[0][i] = i;
    }

    for (int i = 1; i <= lg[tour_length]; ++i) {
        for (int j = 1; j <= tour_length; ++j) {
            if ((1 << i) <= j) {
                rmq[i][j] = rmq[i - 1][j];
                if (level[rmq[i][j]] > level[rmq[i - 1][j - (1 << (i - 1))]]) {
                    rmq[i][j] = rmq[i - 1][j - (1 << (i - 1))];
                }
            }
        }
    }
}
/// Calculates and returns the LCA of 2 nodes x and y
int get_LCA(int &x, int &y, vector <vector<int> > &rmq, vector <int> &lg,
            vector <int> &euler, vector<int> &first, vector <int> &level) {
    x = first[x];
    y = first[y];
    if (x > y) {
        swap(x, y);
    }
    int mid = lg[y - x + 1];
    int ans = rmq[mid][y];
    if (level[ans] > level[rmq[mid][x + (1 << mid) - 1]]) {
        ans = rmq[mid][x + (1 << mid) - 1];
    }
    return euler[ans];
}

int main() {
    freopen("lca.in", "r", stdin);
    freopen("lca.out", "w", stdout);
    int n; // Tree size
    int q; // Number of queries
    // Input
    scanf("%d%d", &n, &q);

    vector< vector<int> > children(n + 1); // List of children for each node
    for (int i = 2; i <= n; ++i) {
        int x; // Father of node i
        scanf("%d", &x);
        children[x].push_back(i);
    }

    vector <int> euler; // Euler tour of a tree
    euler.push_back(0); // index from 1

    vector <int> level; // Level of a node in the Euler tour
    level.push_back(0); // index from 1

    vector <int> first(n + 1); // Level of a node in the Euler tour

    generate_euler_tour(children, euler, level, first);
    int tour_length = euler.size() - 1; // Length of the Euler tour

    vector <int> lg (tour_length + 1, 0);
    for (int i = 2; i <= tour_length; ++i) {
        lg[i] = 1 + lg[(i >> 1)]; // Vector of base 2 logarithms
    }

    vector <vector <int> > rmq(lg[tour_length] + 1, vector <int> (tour_length + 1, 0)); // RMQ
    build_rmq(rmq, lg, tour_length, level);

    // Queries
    for (int i = 1; i <= q; ++i) {
        int x, y; // Two nodes
        scanf("%d%d", &x, &y);
        printf("%d\n", get_LCA(x, y, rmq, lg, euler, first, level));
    }

    return 0;
}