// compile: make data
// run: ./data < data.in
#include <bits/stdc++.h>
using namespace std;
#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt")
#ifdef LOCAL
#include <debug/codeforces.h>
#define debug(x...) _debug_print(#x, x);
#define Debug(x...) _debug_print_format(#x, x);
#else
#define debug(x...)
#define Debug(x...)
#endif
template<typename...Args> void print_(Args...args){((cout<<args<<" "),...)<<endl;}
#define VI vector<int>
#define VII vector<vector<int>>
#define VIII vector<vector<vector<int>>>
#define rep(i,a,b) for(int i=(a);i<(int)(b);++i)
#define sz(v) ((int)(v).size())
#define print(...) print_(__VA_ARGS__);
#define FIND(a, x) ((find(a.begin(),a.end(),(x))!=a.end())?1:0)
#define cmin(x,...) x=min({(x), __VA_ARGS__})
#define cmax(x,...) x=max({(x), __VA_ARGS__})
#define INTMAX (int)(9223372036854775807)
#define INF (int)(1152921504606846976)
#define NaN (int)(0x8b88e1d0595d51d1)
#define double long double
#define int long long
#define MAXN 200010
struct Tree {
int n;
vector<vector<int>> e;
struct node {
vector<node*> ch;
node* parent = nullptr;
int size, depth;
};
vector<node> vertex;
node *root;
Tree(int V) {
n = V;
e.resize(n);
vertex.resize(n);
}
void add_edge(int u, int v) {
e[u].push_back(v), e[v].push_back(u);
}
int ind(node *x) {return x - &vertex[0]; }
void build(int rt = 0) {
function<void(int, int)> dfs = [&](int u, int pre) {
vertex[u].size = 1;
vertex[u].depth = u==ind(root) ? 0 : vertex[u].parent->depth + 1;
for (int v: e[u]) {
if (v == pre) continue;
vertex[u].ch.push_back(&vertex[v]);
vertex[v].parent = &vertex[u];
dfs(v, u);
vertex[u].size += vertex[v].size;
}
};
root = &vertex[rt];
dfs(rt, -1);
}
void graphviz_dump(int plus = 0, string filename = "graph.dot") {
FILE *f = fopen(filename.c_str(), "w");
fprintf(f, "digraph Tree {\n");
rep(i, 0, n) {
node *x = &vertex[i];
fprintf(f, " %lld;\n");
}
rep(i, 0, n) {
node *x = &vertex[i];
for (auto y: x->ch) {
fprintf(f, " %ld -> %ld;\n", x - &vertex[0], y - &vertex[0]);
}
}
fprintf(f, "}\n");
}
vector<vector<int>> hp;
vector<vector<int>> ancestor() {
vector<vector<int>> p(n, vector<int>(log2(n) + 1));
rep(i, 0, n) p[i][0] = vertex[i].parent ? ind(vertex[i].parent) : -1;
rep(j, 1, log2(n)+1) rep(i, 0, n) p[i][j] = ~p[i][j-1] ? p[p[i][j-1]][j-1] : -1;
return p;
}
int lca(int u, int v) {
if (!hp.size()) hp = ancestor();
if (vertex[u].depth < vertex[v].depth) swap(u, v);
for (int k = log2(n); k >= 0; --k) if (vertex[u].depth - (1<<k) >= vertex[v].depth) u = hp[u][k];
if (u == v) return u;
for (int k = log2(n); k >= 0; --k) {
if (hp[u][k] != hp[v][k]) {
u = hp[u][k], v = hp[v][k];
}
}
return hp[u][0];
}
};
int32_t main() {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
int n, q; cin >> n >> q;
Tree g(n);
rep(i, 0, n-1) {
int x; cin >> x;
g.add_edge(i+1, x-1);
}
g.build(0);
// g.graphviz_dump();
// return 0;
while (q--) {
int u, v; cin >> u >> v; --u, --v;
cout << g.lca(u, v) + 1 << '\n';
}
return 0;
}
OK9casino… Last but not least. Let’s see if this stacks up well against other brands! Let’s inspect ok9casino and assess!
OK9casino… Last but not least. Let’s see if this stacks up well against other brands! Let’s inspect ok9casino and assess!
Win99? Yeah, I downloaded a few games there. Pretty slick setup. Fast downloads too! Worth trying taigamewin99.
Okay, brapublink. Sounds like a shortcut to something…interesting. Proceed with caution, folks! You’ve been warned: brapublink.