参考博客:http://blog.csdn.net/liangzhaoyang1/article/details/52549822
(神犇已经讲的很清晰了)
附模板:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 100000 + 5;
struct Edge
{
int v, next;
Edge(int v = 0, int next = 0) :v(v), next(next) {}
}edge[MAXN << 1];
int head[MAXN], edgenum;//邻接表
int dep[MAXN << 1], tot, first[MAXN], tag[MAXN << 1];//dep为对应坐标的深度,tot为坐标,first为节点第一次出现的坐标,tag为坐标对应的节点编号
int st[MAXN << 1][30];//储存最小深度的坐标
void toInit()
{
tot = 0;
memset(head, -1, sizeof(head));
edgenum = 0;
}
void toAdd(int u, int v)
{
edge[edgenum] = Edge(v, head[u]);
head[u] = edgenum++;
}
void toDfs(int u, int fa, int tier)
{
dep[++tot] = tier;
tag[tot] = u;
first[u] = tot;
for (int i = head[u];i != -1;i = edge[i].next)
{
int v = edge[i].v;
if (v == fa) continue;
toDfs(v, u, tier + 1);
dep[++tot] = tier;
tag[tot] = u;
}
}
void getSt(int n)
{
for (int i = 1;i <= n;++i)
st[i][0] = i;//最小的深度是自己
for (int j = 1;1 << j <= n;++j)
for (int i = 1;i + (1 << j) - 1 <= n;++i)
{
int st1 = st[i][j - 1], st2 = st[i + (1 << j - 1)][j - 1];
st[i][j] = dep[st1] < dep[st2] ? st1 : st2;
}
}
int toRmq(int l, int r)
{
int k = 0;
while (1 << k <= r - l + 1) k++;
k--;
int st1 = st[l][k], st2 = st[r + 1 - (1 << k)][k];
return dep[st1] < dep[st2] ? st1 : st2;//返回最小深度的坐标
}
int toLca(int x, int y)
{
x = first[x], y = first[y];//节点第一次出现的坐标
if (x > y) swap(x, y);//用于rmq左右端点
return tag[toRmq(x, y)];//返回最小深度对应的节点编号
}
int main()
{
int n, q;
scanf("%d%d", &n, &q);
toInit();
for (int i = 2;i <= n;++i)
{
//加边
int pi;scanf("%d", &pi);
toAdd(i, pi);
toAdd(pi, i);
}
toDfs(1, 1, 0);
getSt(tot);//tot=2*n-1;
return 0;
}