这道题我用的是vector存的图,d[]表示该节点的大小(包括自己),fa[i]就表示i这个节点的父亲节点
在dfs的时候进行vector遍历就行
性质:
一个树的重心一定在他所有儿子的子树的重心的连线上。
#include<bits/stdc++.h>
using namespace std ;
const int maxn=300100;
int n,q;
int d[maxn];
vector<int >tree[maxn];
int ans[maxn];
int fa[maxn];
void dfs(int u,int father)
{
d[u]=1;
int minNode=0;
int size=tree[u].size();
ans[u]=u;
for(int i=0;i<size;i++)
{
int v=tree[u][i];
if(v!=father)
{
dfs(v,u);
d[u]+=d[v];
if(d[v]>d[minNode])
minNode=v;
}
}
if(d[minNode]*2>d[u])//minnode表示这个节点的子树中,子节点大小最大的编号
{
int k=ans[minNode];//mindnode的重心一定比这个节点的重心深 ,所以k从这个位置开始一定不会漏掉正确的答案
while(d[u]>d[k]*2)//树的重心近似是一个树的中心位置 ,所以我们让重心的大小尽可能等于该当前你所求节点大小的一半
{
k=fa[k];//k就往上跳,不跳的时候说明找到了
}
ans[u]=k;
}
}
int main()
{
cin>>n>>q;
for(int i=2;i<=n;i++)
{
int x;
cin>>x;
fa[i]=x;
tree[i].push_back(x);
tree[x].push_back(i);
}
dfs(1,0);
for(int i=1;i<=q;i++)
{
int x;
cin>>x;
cout<<ans[x]<<endl;
}
}