Cod sursa(job #1802852)

Utilizator bciobanuBogdan Ciobanu bciobanu Data 10 noiembrie 2016 18:21:33
Problema Lowest Common Ancestor Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 3.13 kb
#include <cstdio>
#include <cctype>
#include <cstring>
using namespace std;

const int NMAX = 100000;
const int BUFFSIZE = 4096;
const int NIL = -1;

inline char GetChar() {
	static char buff[BUFFSIZE];
	static int pos = BUFFSIZE;
	if (pos == BUFFSIZE) {
		fread(buff, 1, BUFFSIZE, stdin);
		pos = 0;
	}
	return buff[pos++];
}

inline int ReadInt() {
	int q = 0;
	char c;
	do {
		c = GetChar();
	} while (not isdigit(c));
	do {
		q = (q << 1) + (q << 3) + (c - '0');
		c = GetChar();
	} while (isdigit(c));
	return q;
}

int pointer[NMAX - 1];
int head[NMAX];

int idx[NMAX], maxIdx[NMAX];
int ancestorHeights[NMAX];
int pathParent[NMAX];

inline int LSB(const int& x) {
	return x & -x;
}

inline int MSB(int x) {
	x |= (x >> 1);
	x |= (x >> 2);
	x |= (x >> 4);
	x |= (x >> 8);
	x |= (x >> 16);
	return (x >> 1);
}

void BuildSchieberVishkin(const int n) {
	static int parent[NMAX], vertices[NMAX];
	
	// dfs
	{
		int stackSize = 1, currIdx = 1;
		while (stackSize) {
			const int node = vertices[--stackSize];
			idx[node] = currIdx++;
			for (int i = head[node]; ~i; i = pointer[i]) {
				const int son = i + 1;
				parent[son] = node;
				vertices[stackSize++] = son;
			}
		}
	}

	// bfs
	{
		int queueFront = 0, queueBack = 1;
		vertices[0] = 0;
		while (queueBack != queueFront) {
			const int node = vertices[queueFront++];
			for (int i = head[node]; ~i; i = pointer[i]) {
				const int son = i + 1;
				vertices[queueBack++] = son;
			}
		}
	}

	memcpy(maxIdx, idx, 4 * n);
	for (int i = n - 1; i >= 0; i -= 1) {
		const int node = vertices[i];
		if (LSB(maxIdx[parent[node]]) < LSB(maxIdx[node])) {
			maxIdx[parent[node]] = maxIdx[node];
		}
	}

	ancestorHeights[0] = 0;
	for (int i = 0; i < n; i += 1) {
		ancestorHeights[vertices[i]] = ancestorHeights[parent[vertices[i]]] | LSB(maxIdx[vertices[i]]);
	}
	
	memcpy(pathParent, parent, 4 * n);
	pathParent[idx[0] - 1] = 0;
	for (int i = 0; i < n; i += 1) {
		const int node = vertices[i];
		for (int j = head[node]; ~j; j = pointer[j]) {
			const int son = j + 1;
			if (maxIdx[node] != maxIdx[son]) {
				pathParent[idx[son] - 1] = node;
			} else {
				pathParent[idx[son] - 1] = pathParent[idx[node] - 1];
			}
		}
	}
}

int Query(const int& x, const int& y) {
	const int Ix = maxIdx[x], Iy = maxIdx[y];
	const int hIx = LSB(Ix), hIy = LSB(Iy);
	const int msbMask = MSB((Ix ^ Iy) | hIx | hIy);
	const int mask = LSB(ancestorHeights[x] & ancestorHeights[y] & ~msbMask);

	int left, right;

	if (mask == hIx) {
		left = x;
	} else {
		const int kMask = MSB(ancestorHeights[x] & (mask - 1));
		left = pathParent[(idx[x] & ~kMask | (kMask + 1)) - 1];
	}

	if (mask == hIy) {
		right = y;
	} else {
		const int kMask = MSB(ancestorHeights[y] & (mask - 1));
		right = pathParent[(idx[y] & ~kMask | (kMask + 1)) - 1];
	}
	return idx[left] < idx[right] ? left : right;
}

int main() {
	freopen("lca.in", "r", stdin);
	freopen("lca.out", "w", stdout);

	int n = ReadInt(), m = ReadInt();

	memset(head, NIL, 4 * n);
	for (int i = 1; i < n; i += 1) {
		const int x = ReadInt() - 1;
		pointer[i - 1] = head[x];
		head[x] = i - 1;
	}

	BuildSchieberVishkin(n);

	while (m--) {
		printf("%d\n", 1 + Query(ReadInt() - 1, ReadInt() - 1));
	}

	return 0;
}