P5536 【XR-3】核心城市(树的直径)

题目描述

X 国有 nn 座城市,n − 1n−1 条长度为 11 的道路,每条道路连接两座城市,且任意两座城市都能通过若干条道路相互到达,显然,城市和道路形成了一棵树。

X 国国王决定将 kk 座城市钦定为 X 国的核心城市,这 kk 座城市需满足以下两个条件:

  1. 这 kk 座城市可以通过道路,在不经过其他城市的情况下两两相互到达。
  2. 定义某个非核心城市与这 kk 座核心城市的距离为,这座城市与 kk 座核心城市的距离的最小值。那么所有非核心城市中,与核心城市的距离最大的城市,其与核心城市的距离最小。你需要求出这个最小值。

输入格式

第一行 22 个正整数 n,kn,k。

接下来 n - 1n−1 行,每行 22 个正整数 u,vu,v,表示第 uu 座城市与第 vv 座城市之间有一条长度为 11 的道路。

数据范围:

  • 1 \le k < n \le 10 ^ 51≤k<n≤105。
  • 1 \le u,v \le n, u \ne v1≤u,v≤n,u​=v,保证城市与道路形成一棵树。

输出格式

一行一个整数,表示答案。

输入输出样例

输入 #1复制

6 3
1 2
2 3
2 4
1 5
5 6

输出 #1复制

1

说明/提示

【样例说明】

钦定 1,2,51,2,5 这 33 座城市为核心城市,这样 3,4,63,4,6 另外 33 座非核心城市与核心城市的距离均为 11,因此答案为 11。

题解

找到树的直径中点,以中点为根找每个节点的子树到新根的深度maxdeep与该节点到新根的深度dep,然后用maxdep[u]-dep[u]就是到u这个核心城市的最远距离,将maxdep[u]-dep[u]从大到小排序,靠前的k个点就是核心城市,易证他们是相互连通的

  

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=2e5+10;
int n,k;
inline int read()
{
	int s=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}
	return s*f;
}
int tot,head[N],nxt[N],adj[N];
void add(int u,int v)
{
	tot++;
	nxt[tot]=head[u];
	head[u]=tot;
	adj[tot]=v;
}
int q,ans=0;//q记录到1最远点的距离,ans记录最远点到1的距离
int dep[N],f[N];//dep记录深度 
void dfs1(int u,int fa)
{
	if(dep[u]>ans)
	{
		ans=dep[u];
		q=u;
	}
	for(int i=head[u];i;i=nxt[i])
	{
		int v=adj[i];
		if(v==fa)continue;
		dep[v]=dep[u]+1;
		dfs1(v,u);
	}
}
void dfs2(int u,int fa)
{
	if(dep[u]>ans)
	{
		ans=dep[u];
		q=u;
	}
	for(int i=head[u];i;i=nxt[i])
	{
		int v=adj[i];
		if(v==fa)continue;
		dep[v]=dep[u]+1;
		f[v]=u;
		dfs2(v,u);
	}
}
int anss[N],maxdep[N];
inline int mx(int x,int y)
{
	return x>y?x:y;
}
void dfs3(int u,int fa)
{
	maxdep[u]=dep[u];
	for(int i=head[u];i;i=nxt[i])
	{
		int v=adj[i];
		if(v==fa)continue;
		dep[v]=dep[u]+1;
		dfs3(v,u);
		maxdep[u]=mx(maxdep[u],maxdep[v]);
	}
}
bool cmp(int p,int q)
{
	return p>q;
}
int main()
{
	n=read();
	k=read();
	int i,x,y;
	for(i=1;i<n;i++)
	{
		x=read();y=read();
		add(x,y);add(y,x);
	}
	dfs1(1,0);
	memset(dep,0,sizeof(dep));
	ans=0;
	dfs2(q,0);
	int tx=q;
	for(i=1;i<=(dep[q]+1)/2;i++)
		tx=f[tx];
	memset(dep,0,sizeof(dep));
	dfs3(tx,0);
	for(i=1;i<=n;i++)
		 anss[i]=maxdep[i]-dep[i];
	sort(anss+1,anss+1+n,cmp);
	ans=0;
	for(i=k+1;i<=n;i++)
		ans=mx(ans,anss[i]+1);
	printf("%d\n",ans);
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值