Pagini recente » Cod sursa (job #1134085) | Romanian IOI Medalists: Careers | Cod sursa (job #1207455) | Cod sursa (job #191627) | Cod sursa (job #2676210)
#include<bits/stdc++.h>
#include<stdio.h>
#include<stdlib.h>
#include <fstream>
#include <iostream>
#include <vector>
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";
}
}