UVA1664题解

UVA1664

题目大意 :

在一棵树上找到一个点,使这个点到其他所有点的路径上的最小边和最大。

分析

我们要使一个节点到每个点的容量和最大,然而每个路径的价值是路径上的最小容量,所以我们将边权从大到小排序保证每次新加入的边不会被已有的边所限制(即已有的边一定不大于所查边)。加入的边一定更新所在路径的权值(所插入的边一定不比路径上已有的边权大)。

因为最后所有节点都会在一张联通图里所以我们只需输出任意存在节点的 \(fa\) 的值即可。

代码如下

#warning by StarMaster
#include<bits/stdc++.h>

using namespace std ;
#define int long long
inline int read()
{
	int x = 0 , f = 1 ;
	char ch = getchar() ;
	while(ch > '9' or ch < '0')
	{
		if(ch == '-') f = -1 ;
		ch = getchar() ;
	}
	while(ch >= '0' and ch <= '9')
	{
		x = (x << 1) + (x << 3) + (ch ^ 48) ;
		ch = getchar() ;
	}
	return x * f ;
}
const int MM = 1e6 + 6666 ;
int n , m , q , res , fa[MM] , siz[MM] , ans[MM] ;
struct node
{
	int x , y , z ;
}a[MM] ;
inline bool cmp (node a , node b)
{
	return a.z > b.z ;
}
inline int Find(int x)
{
	if(x == fa[x]) return x ;
	else return fa[x] = Find(fa[x]) ;
}
inline void Init()\\多组数据 
{
	for(int i = 1 ; i <= n ; i ++)
   	{
   		ans[i] = 0 ;
   		fa[i] = i ;
   		siz[i] = 1 ; 
    }
}
signed main()
{
    while(scanf("%ld" , &n) != EOF)\\神奇多组数据输入法 
    { 
        Init() ;
    	for(int i = 1 ; i < n ; i ++)
    	{
    		a[i].x = read() , a[i].y = read() , a[i].z = read() ;
    	}
    	sort(a + 1 , a + n , cmp) ;
		for(int i = 1 ; i < n ; i ++)\\合并时使容量小的集合并到容量大的集合代表节点上中这条边一定会被容量小的集合中的每个节点走一遍(因为是一棵树)所以乘上size, 
		{
			int fx = Find(a[i].x) , fy = Find(a[i].y) , val = a[i].z ;  
			int f1 = ans[fx] + siz[fy] * val , f2 = ans[fy] + siz[fx] * val ;
			if(f1 > f2)
			{
				fa[fy] = fx ;
				siz[fx] += siz[fy] ;
				ans[fx] = f1 ;
			}
			else
			{
				fa[fx] = fy ;
				siz[fy] += siz[fx] ;
				ans[fy] = f2 ;
			}
		}
		cout << ans[Find(1)] << '\n' ; // 最后肯定在一个集合中 
	}
	return 0 ;
}

完结撒花٩(๑>◡<๑)۶

posted @ 2021-10-29 16:08  theStarMaster  阅读(39)  评论(0编辑  收藏  举报