D. Maximum Distance(最小生成树)

Problem - D - Codeforces

 

Chouti已经厌倦了乏味的作业,于是他打开了数年前创建的一个旧编程问题。

给定一个具有n个节点和m条加权边的连通无向图。其中有k个特殊节点:x1,x2,...,xk。

现在定义路径的成本为其边权的最大值。两个顶点之间的距离定义为连接它们的路径的最小成本。

对于每个特殊节点,请找到与其距离最远(根据上述定义,即相应距离是可能的最大值)的另一个特殊节点,并输出它们之间的距离。

由于原始限制非常小,所以他认为这个问题很无聊。现在,他提高了限制,并希望您能为他解决这个问题。

输入 第一行包含三个整数n、m和k(2≤k≤n≤105,n−1≤m≤105)——节点数、边数和特殊节点数。

第二行包含k个不同的整数x1,x2,…,xk(1≤xi≤n)。

接下来的m行,每行包含三个整数u、v和w(1≤u,v≤n,1≤w≤109),表示存在一条权值为w的边连接u和v。给定的图是无向的,因此边(u,v)可以在两个方向上使用。

图可能有多条边和自环。

保证图是连通的。

输出 第一行应包含k个整数。第i个整数是xi与离它最远的特殊节点之间的距离。

Examples

input

Copy

2 3 2
2 1
1 2 3
1 2 2
2 2 1

output

Copy

2 2 

input

Copy

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

output

Copy

3 3 3 

在第一个例子中,顶点 1 和顶点 2 之间的距离等于 2,因为它们之间有一条权重为 2 的边。因此,对于顶点 1 和顶点 2 来说,到最远节点的距离都是 2。

在第二个例子中,可以发现顶点 1 和顶点 2 之间、顶点 1 和顶点 3 之间的距离都是 3,而顶点 2 和顶点 3 之间的距离是 2。

该图可能存在多个边和自环,如第一个例子所示。

题解:
由于我们找的是特殊节点之间的最短距离,这道题比较特殊的是两点间的路径长度为,中间遍历过的最大边权值

由于题中两点距离是最小成本,相当于两点最小的路径长度,既然求的最小我们可以先利用最小生成树,把不需要的边去掉,这样一定最优

现在就变成了一棵树了,那么从任意一个特殊点开始,到其他所有特殊点,中途遍历过最长的边权,就是

离它最远的特殊节点之间的距离

这个距离对于所有特殊点,都适用

因为我们是从一个特殊点开始的,我们找的这个最长边权的两侧,肯定都有特殊点,这样两边的点都可以经过这个最长边权

#include <cstdio>
#include <cstring>
#include <algorithm>
#include<iostream>
#include<vector>
#include<set>
#include<map>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;
#define int long long
typedef pair<int,int> PII;
int mod = 998244353;
int n,m,k;
struct node
{
	int l,r,x;
}a[100050];
int b[100050];
int f[100050];
int cmp(node a,node b)
{
	return a.x < b .x;
}
int find(int x)
{
	if(f[x] == x)
	return x;
	return f[x] = find(f[x]);
}
vector<PII> p[100050];
int d[100050];
void dfs(int x,int fa)
{
	for(PII ne:p[x])
	{
		if(ne.first == fa)
		continue;
		d[ne.first] = max(d[x],ne.second);
		dfs(ne.first,x);
	}
}
void solve()
{
	cin >> n >> m >> k;
	for(int i = 1;i <= k;i++)
	{
		cin >> b[i];
	}
	for(int i = 1;i <= m;i++)
	{
		cin >> a[i].l >> a[i].r >> a[i].x; 
	}
	for(int i = 1;i <= n;i++)
	f[i] = i; 
	sort(a + 1,a + 1 + m,cmp);
	for(int i = 1;i <= m;i++)
	{
		int x = find(a[i].l);
		int y = find(a[i].r);
		if(x != y)
		{
			f[x] = y;
			p[a[i].l].push_back({a[i].r,a[i].x});
			p[a[i].r].push_back({a[i].l,a[i].x});
		}
	}
	dfs(b[1],0);
	int ma = 0;
	for(int i = 1;i <= k;i++)
	ma = max(ma,d[b[i]]);
	for(int i = 1;i <= k;i++)
	cout << ma <<" ";
}
//5 7 8 9 10

signed main()
{
//	ios::sync_with_stdio(0);
//	cin.tie(0);cout.tie(0);
	int t = 1;
//	cin >> t;
	while(t--)
	{
		solve(); 
	}
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值