树的相关预处理(深度,高度,子节点数,直径,重心)

因为树不会存在环,所以在dfs树的时候不必vis,只需不走回头路v!=fa即可

一.树的高度与深度

void dfs(int u,int fa){
    
    
	dep[u]=dep[fa]+1;//u比 fa深 1 
	size[u]=1;//u节点自己算一个 
	high[u]=1;
	for(int i=vex[u];i;i=e[i].next){
    
    
		int v=e[i].v;
		if(v==fa)continue;
		dfs(v,u); 
		size[u]+=size[v];//父节点的节点数等于所有子树的节点数之和 
		high[u]=high[v]+1;//只有叶子节点 high会不被修改,始终如 1 
	}
}

二.树的直径

定义:树中相邻最远的两个点的距离,即maxdis(s,t)
算法:从任意出发,求出最远点s,再从s出发,求出最远点t
则:树的直径 = dis(s,t)

void dfs(int u,int fa){
    
     
	for(int i=vex[u];i;i=e[i].next){
    
    
		int v=e[i].v;
		if(v==fa)continue;
		dis[v]=dis[u]+e[i].c;
		dfs(v,u); 
	}
}
int findmaxdis(){
    
    
	dfs(1);
	int s=0,t,maxdis=-1e9;
	for(int i=1;i<=n;i++){
    
    
		if(dis[i]>maxdis){
    
    
			maxdis=dis[i];
			s=i;
		}
		dis[i]=0;
	}
	
	dfs(s);
	maxdis=-1e9;
	for(int i=1;i<=n;i++){
    
    
		if(dis[i]>maxdis){
    
    
			maxdis=dis[i];
			t=i;
		}
		dis[i]=0;
	}
	return maxdis;
	//即树的直径为s-t 
}

三.树的重心(质心)

定义:对于一棵n个节点的树,找到一个点,使得删除该点后的最大连通块节点数最小
性质1:删除重心后所得的所有子树,节点数不超过原树的1/2
性质2:一棵树最多有两个重心
性质3:树中所有点到重心的距离之和最小,如果有两个重心,那两个距离之和相等
性质4:树删除或添加一个叶子节点,重心最多只移动一条边
性质5:两个树通过一条边合并,新的重心在原树两个重心的路径上

根据性质1,写出相应的求重心算法

void dfs(int u,int fa){
    
      
    size[u]=1;
    int maxnode=0;
	for(int i=vex[u];i;i=e[i].next){
    
    
		int v=e[i].v;
		if(v==fa)continue;
		dfs(v,u);
		size[u]+=size[v];
		maxnode=max(maxnode,size[v]);
	}
	maxnode=max(maxnode,n-size[u]);
    //maxnode就是最大的子树节点个数 
	if(maxnode*2<=n)zon[u]=1;
}