#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <cstddef>
#include <utility>
#include <vector>
#include <stack>
#include <map>
#define debug 0
using namespace std;
class dijoint_set {
private:
int size;
vector<int> parent;
vector<int> rank;
public:
dijoint_set(int size) {
parent.resize(size, -1);
rank.resize(size);
}
int get_size() {
return size;
}
vector<int> get_parent_repr() {
return parent;
}
void make_set(int node) {
parent[node] = node;
rank[node] = 1;
}
int find(int node) {
int root = node, aux;
while (root != parent[root]) {
root = parent[root];
}
while (node != root) {
aux = parent[node];
parent[node] = root;
node = aux;
}
return root;
}
void union_set(int x, int y) {
int dadx = find(x), dady = find(y);
if (dadx == dady) {
return;
}
if (rank[dadx] > rank[dady]) {
parent[dady] = dadx;
}
else {
parent[dadx] = dady;
}
if (rank[dadx] == rank[dady]) {
rank[dady]++;
}
}
void set_ancestors(int node, int ancestor) {
int root = find(node);
if (root == find(ancestor)) {
parent[root] = ancestor;
parent[ancestor] = ancestor;
rank[ancestor] = rank[root] + 1;
}
}
};
/* OLCA(u)
MakeSet(u)
u.ancestor := u
for each v in u.children do
TarjanOLCA(v)
Union(u, v)
Find(u).ancestor := u
u.color := black
for each v such that {u, v} in P do
if v.color == black then
print "Tarjan's Lowest Common Ancestor of " + u +
" and " + v + " is " + Find(v).ancestor + "." */
/* void offline_lcaconst(int node, vector<vector<int>> &graph,
const vector<vector<int>> &questions,
dijoint_set &forest) {
size_t i;
int son, local_root;
forest.make_set(node);
for (i = 1; i <= graph[node].size(); i++) {
son = graph[node][i];
offline_lcaconst(son, graph, questions, forest);
forest.union_set(node, son);
local_root = forest.find(node);
forest
*/
/*}
}*/
static pair<int, int> order_pair(int a, int b) {
return make_pair(min(a, b), max(a, b));
}
static pair<int, int> order_pair(pair<int, int> p) {
return make_pair(min(p.first, p.second), max(p.first, p.second));
}
vector<int> lca(const vector<vector<int>> &graph,
const vector<pair<int, int>> &queries) {
vector<vector<int>> tree(graph);
vector<vector<int>> questions(graph.size());
vector<int> answers(queries.size());
stack<int> st;
map<pair<int, int>, int> results;
pair<int, int> query_pair;
vector<bool> visited(graph.size(), false);
size_t i;
int node, son;
dijoint_set forest(graph.size());
for (i = 0; i < queries.size(); i++) {
int a = queries[i].first, b = queries[i].second;
questions[a].push_back(b);
questions[b].push_back(a);
}
for (i = 0; i < graph.size(); i++) {
forest.make_set(i);
// visited[i] = false;
}
st.push(0);
while (!st.empty()) {
node = st.top();
if (debug)
printf("%d\n", node + 1);
// if node has no more unprocessed sons
if (tree[node].size() == 1) {
visited[node] = true;
// iterate through the list of questions
for(const auto& other: questions[node]) {
query_pair = order_pair(node, other);
// if we have note processed any answers for this query
if (visited[other] && results.find(query_pair) == results.end()) {
results[query_pair] = forest.find(other);
if (debug)
printf("Query: %d %d %d\n", query_pair.first + 1, query_pair.second + 1, results[query_pair] + 1);
}
}
// unite node with his father
if (debug)
printf("unite\n");
forest.union_set(node, tree[node][0]);
if (debug)
printf("set_an\n");
// set the ancestor of node's dijoint set to be the node's parent
forest.set_ancestors(node, tree[node][0]);
// finished processing node
st.pop();
}
else {
// apply the recursive algorithm on the first son
son = tree[node].back();
if (debug)
printf("node: %d son:%d\n", node + 1, son + 1);
tree[node].pop_back();
st.push(son);
}
}
for (i = 0; i < queries.size(); i++) {
query_pair = order_pair(queries[i]);
answers[i] = results[query_pair];
}
return answers;
}
using namespace std;
void read_data(const char *in_file, vector<vector<int>> &graph,
vector<pair<int, int>> &queries) {
unsigned int N, M, i, j, k;
//if (in_file != NULL) {
if (freopen("lca.in", "rt", stdin) == NULL) {
exit(1);
}
//}
scanf("%u%u", &N, &M);
graph.resize(N, vector<int>(1));
for (i = 2; i <= N; i++) {
scanf("%u", &j); // we read the father of node i
// because we index at 0 we read j-1 is the father of i - 1
graph[i - 1][0] = j - 1;
graph[j - 1].push_back(i - 1);
}
for (i = 0; i < M; i++) {
scanf("%u%u", &j, &k);
queries.push_back(make_pair(j - 1, k - 1));
}
fclose(stdin);
}
void print_data(const char *out_file, const vector<int> &answers) {
unsigned int i;
//if (out_file != NULL) {
if (freopen("lca.out", "wt", stdout) == NULL) {
exit(2);
}
//}
for (i = 0; i < answers.size(); i++) {
printf("%d\n", answers[i] + 1);
}
fclose(stdout);
}
int main(int argc, char *argv[]) {
vector<vector<int>> graph;
vector<pair<int, int>> queries;
vector<int> answers;
if (argc > 3) {
perror("Please use maximum two files\n");
return -1;
}
read_data(argv[1], graph, queries);
answers = lca(graph, queries);
print_data(argv[2], answers);
return 0;
}