重心的定义是:以这个点为根,那么所有的子树(不算整个树自身)的大小都不超过整个树大小的一半。
1.树中所有点到某个点的距离和中,到重心的距离和是最小的;如果有两个重心,那么他们的距离和一样。
2.把两个树通过一条边相连得到一个新的树,那么新的树的重心在连接原来两个树的重心的路径上。
3.把一个树添加或删除一个叶子,那么它的重心最多只移动一条边的距离。
一棵树的重心是它的子树的重心和这棵树的祖宗节点连的几条线中的其中一点(2)
每推一个点所支配的子树时 它的重心是它分支的重心往上遍历当首次出现这个点支配的点的数量减去分支重心支配的点的数量小于等于这个点支配数量的二分之一时,这时往上遍历的这个点就是这棵子树的重心,此时的重心的所支配的(所有子节点的数量)保证也小于等于这棵子树点的数量的二分之一
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#include<iostream>
#define maxn 300005
using namespace std;
int n,m;
int link[maxn],fa[maxn],ans[maxn];
vector<int>ve[maxn];
void dfs(int pre)
{
link[pre] = 1;
for(int i=0;i<ve[pre].size();i++)
{
dfs(ve[pre][i]);
link[pre]+=link[ve[pre][i]];
}
int ans2 = pre;
bool sym = false;
for(int i=0;i<ve[pre].size();i++)
{
int pre2 = ans[ve[pre][i]];
while((link[pre]-link[pre2])*2>=link[pre])pre2 = fa[pre2];
if(pre2!=pre)
{
ans2 = pre2;
break;
}
}
ans[pre] = ans2;
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=2;i<=n;i++)
{
int pre;
scanf("%d",&pre);
fa[i] = pre;
ve[pre].push_back(i);
}
dfs(1);
while(m--)
{
int pre;
scanf("%d",&pre);
printf("%d\n",ans[pre]);
}
return 0;
}