Cod sursa(job #571896)

Utilizator andra23Laura Draghici andra23 Data 4 aprilie 2011 20:59:52
Problema Lowest Common Ancestor Scor 40
Compilator cpp Status done
Runda Arhiva educationala Marime 3.3 kb
// complexitate <O(nlog(n), O(1)>

#include<fstream>
#include<vector>
#include<iostream>

using namespace std;

const int maxn = 100010;
const int maxm = 2000010;

int t[maxn];
vector <int> v[maxn];
int nd[2*maxn+20], dn[2*maxn+20];
int tour[4*maxn+20], ap[2*maxn+20];
int significant[5*maxn];
int leftk[5*maxn], rightk[5*maxn];
vector <int> pmin[5*maxn], smin[5*maxn];
ofstream g("lca.out");

void dfs(int nod, int &i, int &k) {
	i++; k++;
	int actual = i;
	nd[nod] = i;
	dn[i] = nod;
	tour[k] = i;
	ap[i] = k;
	for (int j = 0; j < v[nod].size(); j++) {
		dfs(v[nod][j], i, k);
		k++;
		tour[k] = actual;	
	}
}

int buildTree(int pos, int dec, int &i) {
	int actual;
	if (pos > dec) {
		i++;
		actual = i;
		pmin[i].push_back(tour[(i+1)/2]);
		smin[i].push_back(tour[(i+1)/2]);
		leftk[i] = -1;
		rightk[i] = -1;
		return i;
	}
	else {
		int left_son = buildTree(2*pos, dec, i);
		i++;
		actual = i;
		int right_son = buildTree(2*pos+1, dec, i);
		
		leftk[actual] = left_son;
		rightk[actual] = right_son; 
		
		//actualizare pmin
		pmin[actual] = pmin[left_son];
		int last = pmin[actual].size()-1;
		for (int j = 0; j < pmin[right_son].size(); j++) {
			if (pmin[right_son][j] < pmin[actual][last])
				pmin[actual].push_back(pmin[right_son][j]);
			else 
				pmin[actual].push_back(pmin[actual][last]);
			last++;	
		}
		
		//actualizare smin
		int first = smin[right_son][0];
		for (int j = 0; j < smin[left_son].size(); j++) {
			if (smin[left_son][j] < first)
				smin[actual].push_back(smin[left_son][j]);
			else
				smin[actual].push_back(first); 
		}
		for (int j = 0; j < smin[right_son].size(); j++)
			smin[actual].push_back(smin[right_son][j]);
	}
	
	return actual;
}

int treeQuery(int x, int y) {
	int z = x^y;
	int k = significant[z];
	x = x >> k-1;
	if (x % 2 == 0)
		x++;
	x = x << k-1;
	return x; 
}

int main() {
	ifstream f("lca.in");
	
	int n, m;
	f >> n >> m;
	int x, y;
	
	t[1] = -1;
	for (int i = 2; i <= n; i++) {
		f >> x;
		t[i] = x;
		v[x].push_back(i);	
	}
	
	int number1 = 0, number2 = 0;
	dfs(1, number1, number2);
	
	int leafs = 2*n-1;
	int total_leafs = 1;
	while (total_leafs < leafs) 
		total_leafs = total_leafs*2;		
	
	int dec = total_leafs-1;
	
	number1 = 0;
	buildTree(1, dec, number1);
	
	significant[1] = 1;
	int next = 2;
	for (int i = 2; i <= 2*total_leafs-1; i++) {
		if (i == next) {
			significant[i] = significant[i-1]+1;
			next = next<<1;	
		}
		else 
			significant[i] = significant[i-1];
	}
	
	for (int i = 1; i <= m; i++) {
		f >> x >> y; 
		int res;
		if (x == y)
			res = x;
		else {
			int dx = nd[x];
			int dy = nd[y];
			int tx = ap[dx];
			int ty = ap[dy];
			if (tx > ty) {
				int aux = tx;
				tx = ty;
				ty = aux;	
			}
			int qx = (tx-1)*2+1;
			int qy = (ty-1)*2+1;
			res = treeQuery(qy, qx);
			
			if (res%2 == 1) 
				res = dn[(res+1)/2];	
			else {
				int left_son = leftk[res];
				int right_son = rightk[res];
				int size = smin[left_son].size();
				int pos_left = (tx-1)%size;
				int pos_right = (ty-1)%size;
				
				int minx = smin[left_son][pos_left];
				int miny = pmin[right_son][pos_right];
				if (minx < miny)
					res = minx;
				else res = miny;
				res = dn[res];
			}
		}
		
		g << res << '\n';
	}
	
	return 0;
}