#include <iostream>
#include <fstream>
#include <vector>
// class lca_tarjan {
// std::vector< std::vector<int> > children;
// std::vector< pair< int, int> > query;
// bool *vis;
// int *ancestor;
// public:
// lca_tarjan();
// lca_tarjan(const int &n) {
// children.resize(n + 1);
// // squery.resize(m);
// vis = new bool[n + 1];
// ancestor = new int[n+ 1];
// }
// void addInTree(const int &father, const int &child) {
// children[father].push_back(child);
// }
// ~lca_tarjan() {
// delete vis;
// delete ancestor;
// }
// int findParent(const int &nod) {
// if (nod != parent[nod]) {
// parent[nod] = findParent(parent[nod]);
// }
// return parent[nod];
// }
// void makeDisjointUnion(const int &node1, const int &node2) {
// }
// void dfsTarjan(const int &nod) {
// vis[nod] = 1;
// ancestor[nod] = nod;
// for (int i = 0; i < children[nod].size(); ++i) {
// dfsTarjan(children[nod][i]);
// }
// }
// void solve() {
// }
// };
void mySwap (int &a, int &b) {
a = a ^ b;
b = a ^ b;
a = a ^ b;
}
int findParent(int &node, int *parent) {
if (node != parent[node])
parent[node] = findParent(parent[node], parent);
return parent[node];
}
void makeUnion (int &node1, int &node2, int *parent, int *rank) {
int root1 = findParent(node1, parent);
int root2 = findParent(node2, parent);
// std::cout << node1 <<"Da\n";
if (root1 != root2) {
if (rank[root1] < rank[root2])
mySwap(root1, root2);
parent[root2] = root1;
if (rank[root1] == rank[root2])
rank[root1]++;
}
}
void recursiveDfs(int &node, std::vector<std::vector<int>> &graph,
std::vector< std::vector< std::pair<int, int> > >& queries, bool *visited,
int *ancestor, int *parent, int *rank, std::vector<int> &answer) {
parent[node] = node;
ancestor[node] = node;
rank[node] = 1;
visited[node] = 1;
for (int i = 0; i < graph[node].size(); ++i) {
if (!visited[graph[node][i]]) {
// std::cout << graph[node][i] << "Da\n";
recursiveDfs(graph[node][i], graph, queries, visited,
ancestor, parent, rank, answer);
makeUnion(node, graph[node][i], parent, rank);
ancestor[findParent(node, parent)] = node;
}
}
for (int i = 0; i < queries[node].size(); ++i) {
if (visited[queries[node][i].first] == 1)
answer[queries[node][i].second] =
ancestor[findParent(queries[node][i].first, parent)];
}
}
std::vector<int> lca(std::vector<std::vector<int>> &graph,
std::vector< std::pair<int, int> > &queries) {
// std::vector<bool> visited(graph.size());
bool *visited;
int node = 1, *ancestor, *rank, *parent;
std::vector<int> answer(queries.size(), 0);
std::vector< std::vector< std::pair<int, int> > > eachNodeQuery(graph.size());
for (int i = 0; i < queries.size(); ++i) {
eachNodeQuery[queries[i].first].push_back({queries[i].second, i});
eachNodeQuery[queries[i].second].push_back({queries[i].first, i});
}
// std::vector<int> answer;
visited = new bool[graph.size()] {0};
ancestor = new int[graph.size()] {0};
parent = new int[graph.size()] {0};
rank = new int[graph.size()] {1};
recursiveDfs(node, graph, eachNodeQuery, visited, ancestor, parent, rank, answer);
// std::cout << "\n";
// for (int i = 0; i < graph.size(); ++i) {
// std::cout << ancestor[i] << " ";
// }
// std::cout << "\n";
// TODO
// std::cout << queries.size() << "\n";
delete [] visited;
delete [] ancestor;
delete [] rank;
delete [] parent;
return answer;
}
int main () {
std::ifstream fin("lca.in");
std::ofstream fout("lca.out");
int n, m, parent, node1, node2;
std::vector< std::vector<int> > graph;
std::vector< std::pair<int, int> > queries;
fin >> n >> m; // number of nodes and queries
graph.resize(n + 1);
// lca_tarjan obj(n);
for (int i = 2; i <= n; ++i) {
// fin >> node1 >> node2;
// obj.addInTree(parent, i);
fin >> node1;
graph[node1].push_back(i);
graph[i].push_back(node1);
}
for (int i = 0; i < m; ++i) {
fin >> node1 >> node2;
queries.push_back({node1, node2});
}
std::vector<int> ans = lca(graph, queries);
for (int i = 0; i < ans.size(); ++i) {
fout << ans[i] << "\n";
}
// std::cout << "\n" << ans.size() << "\n";
return 0;
}