树的重心

题面跳转

这道题我用的是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;
	}

}
原文地址:https://www.cnblogs.com/bangdexuanyuan/p/13626073.html