Pagini recente » Cod sursa (job #1193771) | Cod sursa (job #2599305) | Cod sursa (job #1411016) | Cod sursa (job #2603039) | Cod sursa (job #2231418)
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
InputStream inputStream = new FileInputStream("lca.in");
OutputStream outputStream = new FileOutputStream("lca.out");
try (InputReader inputReader = new InputReader(inputStream);
PrintWriter printWriter = new PrintWriter(outputStream)) {
int N = inputReader.nextInt();
int M = inputReader.nextInt();
Tree tree = new Tree(N);
for (int node = 2; node <= N; node++) {
int parent = inputReader.nextInt();
tree.addEdge(parent, node);
}
LCASolver solver = new LCASolver(tree);
for (int queryNo = 1; queryNo <= M; queryNo++) {
printWriter.println(solver.getLca(inputReader.nextInt(), inputReader.nextInt()));
}
}
}
static class LCASolver {
private Tree tree;
private int[] depth;
private int[] eulerPosStart;
private int[] eulerRepr;
private int eulerLastPos;
private int[] log2;
private int[][] nodeOfMinDepthInInterval;
public LCASolver(Tree tree) {
this.tree = tree;
this.depth = new int[tree.getNumberOfNodes() + 1];
this.eulerPosStart = new int[tree.getNumberOfNodes() + 1];
this.eulerRepr = new int[tree.getNumberOfNodes() * 2 + 1];
Arrays.fill(depth, 0);
eulerTraversal(tree.getRoot());
this.log2 = new int[eulerLastPos + 1];
Arrays.fill(log2, 0);
for (int i = 2; i <= eulerLastPos; i++) {
log2[i] = log2[i >> 1] + 1;
}
nodeOfMinDepthInInterval = new int[log2[eulerLastPos] + 1][eulerLastPos + 1];
computeMinDepthIntervals();
}
private int getSmallerNode(int node1, int node2) {
return depth[node1] < depth[node2] ? node1 : node2;
}
private void computeMinDepthIntervals() {
for (int pos = 1; pos <= eulerLastPos; pos++) {
nodeOfMinDepthInInterval[0][pos] = eulerRepr[pos];
}
for (int depth = 1, intervalLength = 2; depth <= log2[eulerLastPos]; depth++, intervalLength *= 2) {
// interval: [pos, pos + intervalLength - 1]
for (int pos = 1; pos <= eulerLastPos - intervalLength + 1; pos++) {
nodeOfMinDepthInInterval[depth][pos] = getSmallerNode(
nodeOfMinDepthInInterval[depth - 1][pos],
nodeOfMinDepthInInterval[depth - 1][pos + intervalLength / 2]);
}
}
}
private void eulerTraversal(int node) {
eulerRepr[++eulerLastPos] = node;
eulerPosStart[node] = eulerLastPos;
for (int neighbour : tree.getEdges(node)) {
depth[neighbour] = depth[node] + 1;
eulerTraversal(neighbour);
eulerRepr[++eulerLastPos] = node;
}
}
private int getSmallestNodeInInterv(int startInterv, int endInterv) {
int logIntervLength = log2[endInterv - startInterv + 1];
return getSmallerNode(
nodeOfMinDepthInInterval[logIntervLength][startInterv],
nodeOfMinDepthInInterval[logIntervLength][endInterv - (1 << logIntervLength) + 1]);
}
public int getLca(int firstNode, int secondNode) {
// translating the path between the nodes to a path in the euler traversal
if (eulerPosStart[firstNode] < eulerPosStart[secondNode]) {
return getSmallestNodeInInterv(eulerPosStart[firstNode], eulerPosStart[secondNode]);
}
return getSmallestNodeInInterv(eulerPosStart[secondNode], eulerPosStart[firstNode]);
}
}
static class Tree {
private int N;
private List<List<Integer>> edges;
public Tree(int N) {
edges = new ArrayList<>(N + 1);
this.N = N;
for (int i = 0; i <= N; i++) {
edges.add(new ArrayList<>());
}
}
public void addEdge(int from, int to) {
edges.get(from).add(to);
}
public List<Integer> getEdges(int from) {
return edges.get(from);
}
public int getNumberOfNodes() {
return N;
}
public int getRoot() {
return 1;
}
}
static class InputReader implements AutoCloseable {
private BufferedReader bufferedReader;
private StringTokenizer stringTokenizer;
public InputReader(InputStream inputStream) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
stringTokenizer = null;
}
private String nextToken() {
if (stringTokenizer == null || !stringTokenizer.hasMoreTokens()) {
try {
stringTokenizer = new StringTokenizer(bufferedReader.readLine());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return stringTokenizer.nextToken();
}
private int nextInt() {
return Integer.parseInt(nextToken());
}
@Override
public void close() throws IOException {
bufferedReader.close();
}
}
}