// 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.
Alright, giving 80wim a whirl. Interface is pretty clean and easy to use. Nothing too flashy, but it gets the job done. They seem to have alright odds. Give it a look: 80wim.
Fancy a punt? I checked out 88phatbet and reckon it’s worth a look. Decent odds, and the interface isn’t completely rubbish. Nice one! 88phatbet
Bigdaddygamebet, eh? Had a bit of fun on there last night. Good selection of games and things to bet on. Might be back for more! bigdaddygamebet