Cod sursa(job #573445)

Utilizator andra23Laura Draghici andra23 Data 6 aprilie 2011 11:50:40
Problema Lowest Common Ancestor Scor 0
Compilator cpp Status done
Runda Arhiva educationala Marime 4.28 kb
#include<fstream>
#include<vector>
#include<iomanip>

using namespace std;

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

vector <int> v[maxn];
int t[maxn], level[maxn]; 
int ap[2*maxn+10], euler[2*maxn+10], h[2*maxn+10];
int logarithm[2*maxn+10], min_block[2*maxn+10], pos_min_block[2*maxn+10], block_type[2*maxn+10];
int c[maxn][20];
int p[20][20][20], s[20];
int pos_max = 1, h_max = 1;
ofstream g("lca.out");
	
void eulerTour(int nod, int &i) {
	
	i++;
	euler[i] = nod;
	h[i] = level[nod];
	if (h[i] > h_max) {
		h_max = h[i];
		pos_max = i;	
	}
	ap[nod] = i;
	
	for (int j = 0; j < v[nod].size(); j++) {
		level[v[nod][j]] = level[nod]+1;
		eulerTour(v[nod][j], i);
		i++;
		euler[i] = nod;
		h[i] = level[nod];	
	}
}

void buildTable(int size, int k, int &value) {
	int actual, minim;
	if (k == size+1) {
		for (int i = 1; i <= size; i++) {
			p[value][i][i] = i;
			actual = s[i];
			minim = s[i];
			for (int j = i+1; j <= size; j++) {
				p[value][i][j] = p[value][i][j-1];
				actual = actual + s[j];
				if (actual < minim) { 
					p[value][i][j] = j;
					minim = actual;
				}
			}
		}
	}
	else {
		s[k] = -1;
		value = value*2;
		buildTable(size, k+1, value);
		
		s[k] = 1;
		value = value+1;
		buildTable(size, k+1, value);
		
		value--;
		value = value/2;
	}
}

int queryOnC(int x, int y) {
	int length = y-x+1;
	int log_length = logarithm[length];
	int res = c[x][log_length];
	if (min_block[res] > min_block[c[y-(1<<log_length)+1][log_length]])
		res = c[y-(1<<log_length)+1][log_length];
	return pos_min_block[res];
}

int queryOnP(int x, int y, int type) {
	return p[type][x][y];
}

int query(int x, int y, int size) {
	
	//atentie la actualizarea lui res
	int res = pos_max, aux;
	int left, right, block;
	left = (x-1)%size + 1;
	right = size;
	block = (x-1)/size+1;
	if (left != 0) {
		aux = queryOnP(left, right, block_type[block]);
		if (h[(block-1)*size+aux] < h[res])
			res = (block-1)*size+aux;
	}
	//g << res << " " << euler[res] << "/ ";
	
	left = (x-1)/size+1+1;
	right = (y-1)/size;
	if (left <= right) {
		aux = queryOnC(left, right);
		if (h[aux] < h[res])
			res = aux;	
	}
	//g << res << " " << euler[res] << "/ ";
	
	left = 1;
	right = (y-1)%size + 1;
	block = (y-1)/size+1;
	if (right != 0) {
		aux = queryOnP(left, right, block_type[block]);
		if (h[(block-1)*size+aux] < h[res])
			res = (block-1)*size+aux;	
	}
	//g << euler[res] << endl;
	
	return res;
}

int main() {
	ifstream f("lca.in");
	
	int n, m;
	int x, y;
	f >> n >> m;
	
	t[1] = -1;
	for (int i = 2; i <= n; i++) {
		f >> x;
		t[i] = x; 	
		v[x].push_back(i);
	}
	
	level[1] = 1;
	int nr = 0;
	eulerTour(1, nr);

	int total_size = 2*n-1;
	logarithm[1] = 0;
	x = 1; int next = 2;
	for (int i = 2; i <= total_size; i++) {
		logarithm[i] = logarithm[i-1];
		if (i == next) {
			logarithm[i]++;
			next = next<<1;	
		}	
	}
	
	int one_block_size = logarithm[total_size]/2;
	
	int pos = 2, min_block_size = 1;
	x = 2;
	pos_min_block[1] = 1;
	min_block[1] = h[1];
	int value = 1, sign;
	while (pos <= total_size) {
		sign = h[pos] - h[pos-1];
		if (x == one_block_size+1) {
			block_type[min_block_size] = value;
			min_block_size++;
			pos_min_block[min_block_size] = pos;
			min_block[min_block_size] = h[pos];
			x = 2;
			if (sign == -1)
				value = 0;
			else 
				value = 1;
		}
		else {
			if (min_block[min_block_size] > h[pos]) {
				pos_min_block[min_block_size] = pos;
				min_block[min_block_size] = h[pos];	
			}
			x++;
			value = value*2;
			if (sign == 1)
				value++;
		}
		pos++;
	}
	
	//preprocesarea lui min_block 
	for (int i = 1; i <= min_block_size; i++) 
		c[i][0] = i;
		
	for (int j = 1; (1<<j) <= min_block_size; j++) { 
		x = (1<<(j-1));
		for (int i = 1; i+(1<<j)-1 <= min_block_size; i++) {
			c[i][j] = c[i][j-1];
			if (min_block[c[i+x][j-1]] < min_block[c[i][j]]) 
				c[i][j] = c[i+x][j-1];
		}
	}
	
	//preprocesarea blocurilor
	nr = 0;
	buildTable(one_block_size, 1, nr);
	
	int ax, ay, aux;
	for (int i = 1; i <= m; i++) {
		f >> x >> y;	
		ax = ap[x];
		ay = ap[y];
		if (ax > ay) {
			aux = ax;
			ax = ay;
			ay = aux;	
		}
		int res = query(ax, ay, one_block_size);
		res = euler[res];
		
		g << res << '\n';
	}
	
	return 0;
}