LuoGu P3379最近公共父祖先--倍增法 Java实现

我觉得比tarjan要简单。
在进行连续询问输出地时候,不要使用System.out.println().先把结果记录在StringBuilder里面。(我就是因为这样子,所以超时了,还奇怪地找了好长时间原因。)

因为网上有很详细的讲解,这里就是记录一下自己的练习。

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.StringTokenizer;

public class Main {
    static LinkedList<Integer>[] adj;
    static int[] depth;
    static int[][] jumpParent;
    static int maxLevel;

    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        int n = Integer.parseInt(st.nextToken());
        int m = Integer.parseInt(st.nextToken());
        int s = Integer.parseInt(st.nextToken());
        adj = new LinkedList[n + 1];
        for (int i = 0; i <= n; i++) {
            adj[i] = new LinkedList<>();
        }
        int a, b;
        for (int i = 1; i < n; i++) {
            st = new StringTokenizer(br.readLine());
            a = Integer.parseInt(st.nextToken());
            b = Integer.parseInt(st.nextToken());
            adj[a].add(b);
            adj[b].add(a);
        }

        depth = new int[n + 1];
        ArrayDeque<Integer> ad = new ArrayDeque<>();
        ad.addLast(s);
        depth[s] = 1;
        boolean[] isVisit = new boolean[n + 1];
        int curr;
        int maxDepth = 0;
        int[] father = new int[n + 1];
        father[s] = s;
        while (!ad.isEmpty()) {
            curr = ad.pollFirst();
            isVisit[curr] = true;
            for (int next : adj[curr]) {
                if (!isVisit[next]) {
                    ad.addLast(next);
                    depth[next] = depth[curr] + 1;
                    maxDepth = Math.max(depth[next], maxDepth);
                    father[next] = curr;
                }
            }
        }
        maxLevel = 0;
        while (Math.pow(2, maxLevel) < maxDepth) {
            maxLevel++;
        }
        maxLevel++;
        jumpParent = new int[n + 1][maxLevel + 1];
        for (int j = 0; j <= maxLevel; j++) {
            for (int i = 1; i <= n; i++) {
                if (j == 0) {
                    jumpParent[i][j] = father[i];
                    continue;
                }
                jumpParent[i][j] = jumpParent[jumpParent[i][j - 1]][j - 1];
            }
        }
        StringBuilder bu = new StringBuilder();
        for (int i = 1; i <= m; i++) {
            st = new StringTokenizer(br.readLine());
            a = Integer.parseInt(st.nextToken());
            b = Integer.parseInt(st.nextToken());
            bu.append(LCA(a,b)).append("\n");
        }
        System.out.println(bu.toString());
    }

    private static int LCA(int a, int b) {
        if (depth[a] < depth[b]) {
            int temp = a;
            a = b;
            b = temp;
        }
        for (int i = maxLevel; i >= 0; i--) {
            if (depth[jumpParent[a][i]] >= depth[b]) {
                a = jumpParent[a][i];
            }
        }
        if (a == b) {
            return a;
        }
        for (int i = maxLevel; i >= 0; i--) {
            if (jumpParent[a][i] != jumpParent[b][i]) {
                a = jumpParent[a][i];
                b = jumpParent[b][i];
            }
        }
        return jumpParent[a][0];
    }
}

posted @ 2021-04-30 17:38  Monstro  阅读(135)  评论(0)    收藏  举报