Cod sursa(job #2676208)

Utilizator mihail.ungureanuUngureanu Mihail mihail.ungureanu Data 23 noiembrie 2020 18:21:19
Problema Lowest Common Ancestor Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.48 kb
#include<bits/stdc++.h>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
ifstream in("lca.in");
ofstream out("lca.out");
const int MAXN = 100 * 1000;
const int MAXLIST = MAXN * 2;
const int LOG_MAXLIST = 18;
const int SQRT_MAXLIST = 447;
const int MAXBLOCKS = MAXLIST / ((LOG_MAXLIST + 1) / 2) + 1;

int n, root;
vector <int> g [MAXN];
int h [MAXN]; // Vertex height
vector <int> a; // Dfs list
int a_pos [MAXN]; // Positions in dfs list
int block; // Block size = 0.5 log A.size ()
int bt [MAXBLOCKS] [LOG_MAXLIST + 1]; // Sparse table on blocks (relative minimum positions in blocks)
int bhash [MAXBLOCKS]; // Block hashes
int brmq [SQRT_MAXLIST] [LOG_MAXLIST / 2] [LOG_MAXLIST / 2]; // Rmq inside each block, indexed by block hash
int Log2 [2 * MAXN]; // Precalced logarithms (floored values)

// Walk graph
void dfs (int v, int curh) {
	h [v] = curh;
	a_pos [v] = (int) a.size ();
	a.push_back (v);
	for (size_t i = 0; i <g [v] .size (); ++ i)
		if (h [g [v] [i]] == 0) {
			dfs (g [v] [i], curh + 1);
			a.push_back (v);
		}
}

int log (int n) {
	int res = 1;
	while (1 << res <n) ++ res;
	return res;
}

// Compares two indices in a
inline int min_h (int i, int j) {
	return h [a [i]] <h [a [j]]? i: j;
}

// O (N) preprocessing
void build_lca () {
	int sz = (int) a.size ();
	block = (log (sz) + 1) / 2;
	int blocks = sz / block + (sz% block? 1: 0);

	// Precalc in each block and build sparse table
	memset (bt, 255, sizeof bt);
	for (int i = 0, bl = 0, j = 0; i <sz; ++ i, ++ j) {
		if (j == block)
			j = 0, ++ bl;
		if (bt [bl] [0] == -1 || min_h (i, bt [bl] [0]) == i)
			bt [bl] [0] = i;
	}
	for (int j = 1; j <= log (sz); ++ j)
		for (int i = 0; i <blocks; ++ i) {
			int ni = i + (1 << (j-1));
			if (ni >= blocks)
				bt [i] [j] = bt [i] [j-1];
			else
				bt [i] [j] = min_h (bt [i] [j-1], bt [ni] [j-1]);
		}

	// Calc hashes of blocks
	memset (bhash, 0, sizeof bhash);
	for (int i = 0, bl = 0, j = 0; i <sz || j <block; ++ i, ++ j) {
		if (j == block)
			j = 0, ++ bl;
		if (j> 0 && (i >= sz || min_h (i-1, i) == i-1))
			bhash [bl] += 1 << (j-1);
	}

	// Precalc RMQ inside each unique block
	memset (brmq, 255, sizeof brmq);
	for (int i = 0; i <blocks; ++ i) {
		int id = bhash [i];
		if (brmq [id] [0] [0] != -1) continue;
		for (int l = 0; l <block; ++ l) {
			brmq [id] [l] [l] = l;
			for (int r = l + 1; r <block; ++ r) {
				brmq [id] [l] [r] = brmq [id] [l] [r-1];
				if (i * block + r <sz)
					brmq [id] [l] [r] =
						min_h (i * block + brmq [id] [l] [r], i * block + r) - i * block;
			}
		}
	}

	// Precalc logarithms
	for (int i = 0, j = 0; i <sz; ++ i) {
		if (1 << (j + 1) <= i) ++ j;
		Log2 [i] = j;
	}
}

// Answers RMQ in block #bl [l; r] in O (1)
inline int lca_in_block (int bl, int l, int r) {
	return brmq [bhash [bl]] [l] [r] + bl * block;
}

// Answers LCA in O (1)
int lca (int v1, int v2) {
	int l = a_pos [v1], r = a_pos [v2];
	if (l> r) swap (l, r);
	int bl = l / block, br = r / block;
	if (bl == br)
		return a [lca_in_block (bl, l% block, r% block)];
	int ans1 = lca_in_block (bl, l% block, block-1);
	int ans2 = lca_in_block (br, 0, r% block);
	int ans = min_h (ans1, ans2);
	if (bl <br - 1) {
		int pw2 = Log2 [br-bl-1];
		int ans3 = bt [bl + 1] [pw2];
		int ans4 = bt [br- (1 << pw2)] [pw2];
		ans = min_h (ans, min_h (ans3, ans4));
	}
	return a [ans];
}
int main(){
   int N,M;
   cin>>N>>M;
   for(int i=2;i<=N;++i){
       int x;
        in>>x;
       g[x].push_back(i);
   }
   dfs(1,1);
   build_lca();
   for(int i=0;i<M;i++){
       int x,y;
       in>>x>>y;
       out<<lca(x,y)<<"\n";
   }
}