Cod sursa(job #2521496)

Utilizator robertdanRobert Dan robertdan Data 10 ianuarie 2020 23:07:46
Problema Lowest Common Ancestor Scor 20
Compilator java Status done
Runda Arhiva educationala Marime 4.19 kb
//package main;

import java.io.*;
import java.util.ArrayList;

public class Main {

    ArrayList<Integer>[] g;
    int[] rmqDepth;
    int[][] rmq;
    int[] euler;
    int[] depth;
    int eulerIndex;
    int[] parent;
    int[] first;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader("lca.in"));
        PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter("lca.out")));
        Main app = new Main();
        app.solve(br, pw, 1);
        pw.close();
    }

    private void solve(BufferedReader br, PrintWriter pw, int caseNumber) throws IOException {
        String str2 = br.readLine();
        String[] splitString2 = str2.split(" ");
        int N = Integer.parseInt(splitString2[0]);
        int Q = Integer.parseInt(splitString2[1]);
        g = new ArrayList[N + 1];

        for (int j = 1; j <= N; j++) {
            g[j] = new ArrayList<Integer>();
        }
        parent = new int[N + 1];
        String str3 = br.readLine();
        String[] splitString3 = str3.split(" ");
        for (int j = 0; j < N - 1; j++) {
            int father = Integer.parseInt(splitString3[j]);
            g[father].add(j + 2);
            parent[j + 2] = father;

        }
        //precompute depths of nodes
        int root = 1;

        first = new int[N + 1];
        euler = new int[2 * N - 1];
        depth = new int[N + 1];
        eulerIndex = 0;
        eulerFlatTree(root, 0);

        //find the depths of order
        rmqDepth = new int[euler.length];
        for (int l = 0; l < euler.length; l++) {
            rmqDepth[l] = depth[euler[l]];
        }

        //precompute rmq values
        rmqPrecompute();
        for (int q = 0; q < Q; q++) {
            String str5 = br.readLine();
            String[] splitString5 = str5.split(" ");
            //System.out.println(Integer.parseInt(splitString5[0]));
            int fromEulerIndex = first[Integer.parseInt(splitString5[0])];
            //System.out.println(Integer.parseInt(splitString5[1]));
            int toEulerIndex = first[Integer.parseInt(splitString5[1])];
            //System.out.println("From " + fromEulerIndex + " to " + toEulerIndex);
            if(fromEulerIndex > toEulerIndex) {
                int auz = fromEulerIndex;
                fromEulerIndex = toEulerIndex;
                toEulerIndex = auz;
            }
            int ans = rmqQuery(fromEulerIndex, toEulerIndex);
            //System.out.println("Euler[ans] " + euler[ans] + " ans " + ans);
            pw.println(euler[ans]);
        }
    }

    public int rmqQuery(int from, int to) {
        int diff = to - from + 1;
        int pow2diff = 1;
        int exp2 = 0;

        while (2 * pow2diff <= diff) {
            pow2diff *= 2;
            exp2++;
        }

        int tob = from + pow2diff - 1;
        int fromb = to - pow2diff + 1;
        //System.out.println(fromb + " " + exp2);

        int answer = Math.min(rmqDepth[rmq[from][exp2]], rmqDepth[rmq[fromb][exp2]]);

        if (answer == rmqDepth[rmq[from][exp2]]) {
            return rmq[from][exp2];
        }
        return rmq[fromb][exp2];
    }

    public void rmqPrecompute() {
        int n = rmqDepth.length;
        rmq = new int[n][n];

        for (int i = 0; i < n; i++) {
            rmq[i][0] = i;
        }

        for (int k = 1; (1 << k) < n; k++) {
            for (int i = 0; i + (1 << k) - 1 < n; i++) {
                int answer = Math.min(rmqDepth[rmq[i][k - 1]], rmqDepth[rmq[i + (1 << (k - 1))][k - 1]]);
                if (answer == rmqDepth[rmq[i][k - 1]]) {
                    rmq[i][k] = rmq[i][k - 1];
                } else {
                    rmq[i][k] = rmq[i + (1 << (k - 1))][k - 1];
                }
            }
        }
    }

    public void eulerFlatTree(int node, int currentDepth) {
        first[node] = eulerIndex;
        euler[eulerIndex] = node;
        eulerIndex++;
        depth[node] = currentDepth;
        for (int sons : g[node]) {
            eulerFlatTree(sons, currentDepth + 1);
            euler[eulerIndex] = node;
            eulerIndex++;

        }
    }
}