1为根结点,给点其他点的根结点,求以x点为根结点的子树的重心。
树的重心:(删去该结点后,剩下树的sz都小于原来的一半)
1.若所有子结点的sz都小于树sz的一半,那么重心为根
2.若有结点的sz大于树sz的一半,那么重心在以该结点的子树中。重心在该结点到子树重心的路径上。
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
const int maxn = 300000 + 5;
int f[maxn],son_sz[maxn],ans[maxn];
vector<int> mp[maxn];
void dfs(int x,int fa)//x的根为fa
{
int m = 0,pos = x;//在以x为根的子树中,记录最大儿子的结点数
son_sz[x] = 1;
ans[x] = x;
for (int i = 0; i < mp[x].size(); i ++) {
int y = mp[x][i];
if (y != fa) {
dfs(y, x);
son_sz[x] += son_sz[y];//通过dfs记录子树sz
if (son_sz[y] > m) {
m = son_sz[y];
pos = y;
}
}
}
ans[x] = ans[pos];//先记录为最大子树的重心
while (ans[x] != x && son_sz[x] > 2 * son_sz[ans[x]]) {//若以最大子树的重心为根的树的sz,不到原树sz的一半,向上递归即可
ans[x] = f[ans[x]];
}
}
int main()
{
int n,q;
cin >> n >> q;
f[1] = 1;
for (int i = 2; i <= n ; i ++) {
scanf("%d",&f[i]);
mp[i].push_back(f[i]);
mp[f[i]].push_back(i);
}
dfs(1,-1);
int t;
for(int i = 0;i < q;i ++)
{
scanf("%d",&t);
printf("%d\n",ans[t]);
}
return 0;
}