#include <fstream>
#include <vector>
using namespace std;
using Graph = vector<vector<int>>;
constexpr int INF = 2e9;
class LCA {
vector<int> euler, first, level, tree;
vector<bool> visited;
int N, M;
inline void dfs(const Graph& G, int node, int lvl) {
visited[node] = true;
level[node] = lvl;
first[node] = euler.size();
euler.push_back(node);
for (const int adj : G[node])
if (!visited[adj]) {
dfs(G, adj, lvl + 1);
euler.push_back(node);
}
}
inline void build(int node, int l, int r) {
if (l == r) tree[node] = euler[l];
else {
const int mid = (l + r) >> 1;
build(node << 1, l, mid);
build((node << 1) | 1, mid + 1, r);
const int son1 = tree[node << 1];
const int son2 = tree[(node << 1) | 1];
tree[node] = level[son1] < level[son2] ? son1 : son2;
}
}
inline int query(int node, int l, int r, int a, int b) const {
if (a <= l && r <= b) return tree[node];
else {
const int mid = (l + r) >> 1;
int ans1 = INF, ans2 = INF;
if (a <= mid) ans1 = query(node << 1, l, mid, a, b);
if (mid < b) ans2 = query((node << 1) | 1, mid + 1, r, a, b);
if (ans1 == INF) return ans2;
if (ans2 == INF) return ans1;
return level[ans1] < level[ans2] ? ans1 : ans2;
}
}
public:
LCA(const Graph& G, int root) noexcept {
N = G.size();
first.resize(N);
level.resize(N);
visited.resize(N, false);
euler.reserve(2 * N);
dfs(G, root, 0);
M = euler.size();
tree.resize(4 * M);
build(1, 0, M - 1);
}
inline int query(int node1, int node2) const {
int l = first[node1], r = first[node2];
if (l > r) swap(l, r);
return query(1, 0, M - 1, l, r);
}
};
ifstream fin("lca.in");
ofstream fout("lca.out");
int main() {
int N, M, node1, node2;
fin >> N >> M;
Graph G(N);
for (int i = 1; i < N; ++i) {
fin >> node1;
G[node1 - 1].push_back(i);
}
LCA lca(G, 0);
for (int i = 0; i < M; ++i) {
fin >> node1 >> node2;
--node1, --node2;
fout << lca.query(node1, node2) + 1 << '\n';
}
return 0;
}