Cod sursa(job #1361921)

Utilizator vlad.maneaVlad Manea vlad.manea Data 26 februarie 2015 01:41:53
Problema Lowest Common Ancestor Scor 40
Compilator java Status done
Runda Arhiva educationala Marime 3.63 kb
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;

class Node {
	private final int index;
	private final Node father;
	private final List<Node> children;
	
	Node(Node father, int index) {
		this.index = index;
		this.father = father;
		this.children = new ArrayList<Node>();
	}
	
	void addChild(Node node) {
		this.children.add(node);
	}
	
	Node getFather() {
		return father;
	}
	
	int getIndex() {
		return index;
	}
	
	List<Node> getChildren() {
		return children;
	}
}

class LCAFinder {
	private final List<Node> nodes;
	private final List<Integer> euler = new ArrayList<Integer>();
	private List<List<Integer>> rmq = new ArrayList<List<Integer>>();
	private int iter = -1;
	private Map<Node, Integer> first = new HashMap<Node, Integer>();
	private Map<Integer, Node> positions = new HashMap<Integer, Node>();
	private List<Integer> powers = new ArrayList<Integer>();
	
	public LCAFinder(List<Node> nodes) {
		this.nodes = nodes;
		precomputeLCAs();
	}
	
	private void precomputeLCAs() {
		euler(nodes.get(0));
		rmq();
	}
	
	private void euler(Node node) {
		int order = ++iter;
		first.put(node, euler.size());
		positions.put(order, node);
		euler.add(order);
		
		for (Node child : node.getChildren()) {
			euler(child);
			euler.add(order);
		}
	}
	
	private void rmq() {
		int N = euler.size();
		powers.add(0);
		
		// Set the powers of 2 for all lengths.
		for (int l = 0; (1 << l) <= N; ++l) {
			for (int i = (1 << l); i < (1 << (l + 1)); ++i) {
				powers.add(l);
			}
		}
		
		// Make RMQ[0].
		rmq.add(euler);
		
		// Make RMQ[i] using RMQ[i - 1].
		for (int l = 1; (1 << l) <= N; ++l) {
			List<Integer> rmqi = new ArrayList<Integer>();
			
			for (int i = 0; i + (1 << l) <= N; ++i) {
				int left = rmq.get(l - 1).get(i);
				int right = rmq.get(l - 1).get(i + (1 << (l - 1)));
				rmqi.add(Math.min(left, right));
			}
			
			rmq.add(rmqi);
		}
	}
	
	public int findLCA(int x, int y) {
		int firstX = first.get(nodes.get(x));
		int firstY = first.get(nodes.get(y));
		int min = Math.min(firstX, firstY);
		int max = Math.max(firstX, firstY);
		firstX = min;
		firstY = max;
		
		int dist = firstY - firstX + 1;
		int l = powers.get(dist);
		
		int left = rmq.get(l).get(firstX);
		int right = rmq.get(l).get(firstY - (1 << l) + 1);
		int pos = Math.min(left, right);
		return positions.get(pos).getIndex();
	}
}


public class Main {

	public static void main(String[] args) throws IOException {
		InputStream inputStream = new FileInputStream("lca.in");
		Scanner scanner = new Scanner(inputStream);

		OutputStream outputStream = new FileOutputStream("lca.out");
		PrintWriter writer = new PrintWriter(outputStream);
		
		int N = scanner.nextInt();
		int M = scanner.nextInt();
		
		List<Node> nodes = new ArrayList<Node>();
		nodes.add(new Node(null, 0));
		
		for (int i = 1; i < N; ++i) {
			int fatherIndex = scanner.nextInt() - 1;
			Node father = nodes.get(fatherIndex);
			Node node = new Node(father, i);
			father.addChild(node);
			nodes.add(node);
		}
		
		LCAFinder lcaFinder = new LCAFinder(nodes);
		
		while (M-- > 0) {
			int x = scanner.nextInt() - 1;
			int y = scanner.nextInt() - 1;
			int lca = lcaFinder.findLCA(x, y) + 1;
			writer.println(lca);
		}

		writer.flush();

		inputStream.close();
		scanner.close();
		outputStream.close();
		writer.close();
	}
}