树的直径之:【每个点往下走的最大距离】【如何找直径的中点】【P5536】

 

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10,M=2*N;
const int INF=0x3f3f3f3f;
int e[M],ne[M],h[N],idx;
int dis[N];
int mx_dis[N]; //每个点往下走的最远距离 
int fat[N];
int chazhi[N];

void add(int a,int b)
{
	e[idx]=b;
	ne[idx]=h[a];
	h[a]=idx++;
}

void dfs(int u,int fa,int distance)
{
	dis[u]=distance;
	for(int i=h[u];i!=-1;i=ne[i])
    {
    	int j=e[i];
    	if(j==fa) continue;
    	fat[j]=u;
    	dfs(j,u,distance+1);
	}	
}


int dfs2(int u,int fa)
{
	mx_dis[u]=-INF;
	int d2=-INF;
	int dist=-INF;
	
	for(int i=h[u];i!=-1;i=ne[i])
	{
		int j=e[i];
		if(j==fa) continue;
		
		int d=dfs2(j,u)+1;
		dist=max(dist,d);
		
		if(d>=mx_dis[u])
		{
		    d2=mx_dis[u];
		    mx_dis[u]=d;
		}
		else if(d>d2)
		{
			d2=d;
		}
	}
	if(mx_dis[u]==-INF)
	{
		mx_dis[u]=0;
		dist=0;
		d2=0;
	}
	
	return dist;
	
}



int main()
{
	int n,k;
	scanf("%d%d",&n,&k);
	
	memset(h,-1,sizeof h);
	for(int i=0;i<n-1;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		add(u,v);
		add(v,u);
	}
	
	dfs(1,-1,0);
	
	int start;
	int maxv=0;
	
	for(int i=1;i<=n;i++)
	{
		if(dis[i]>maxv)
		{
			maxv=dis[i];
			start=i;
		} 
	}
	
	
	dfs(start,-1,0);
	
	
	int end;
	maxv=0;
	
	for(int i=1;i<=n;i++)
	{
		if(dis[i]>maxv)
		{
			maxv=dis[i];
			end=i;
		} 
	}
	
	fat[start]=0;
	int co=0;
	for(int i=end;i;i=fat[i])
	{
		co++;
	}
	
	int mid=0;
	int cnt=0;
	for(int i=end;i;i=fat[i])
	{
	
	    cnt++;
		if(cnt==(co+1)/2)
		{
			mid=i;
		    break;
	    }
	}

    //目前为止已经找出了直径的中点
	//现在要以直径的中点为总根节点 
	dfs2(mid,-1);  //找出每个点向下走的最大距离 
	
	
	sort(mx_dis+1,mx_dis+1+n);
	reverse(mx_dis+1,mx_dis+1+n);
	
	//第k+1大的是非核心节点 
	cout<<mx_dis[k+1]+1<<endl; //用非核心节点来找核心节点 
	
	
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值