华南理工大学“三七互娱杯”程序设计竞赛 G 并查集

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_38772011/article/details/89644142

https://ac.nowcoder.com/acm/contest/874/G

题意:定义树上任意两点间的权值是经过边权的最大值,求图上任意两点间的权值和

解:每一条边的贡献最多到左右比这条边权值还大的这些点,因此最小的边左右只有2个点(有贡献),

边权排序后,先加小的边,计算联通块大小,贡献为w*val[l]*val[r], 并查集维护联通块大小。

数据好像挺大的,__int128学一学

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int t;
int n;
struct edge{
	ll u,v,w;
}a[1000005];
bool cmp(edge a,edge b)
{
	return a.w<b.w;
}
int pre[1000005];
int val[1000005];
__int128  ans;
int find(int x)
{
	if(x==pre[x])
		return x;
	else
		return pre[x] = find(pre[x]);
 } 

void scan(__int128 &x)
{
    x = 0;
    int f = 1;
    char ch;
    if((ch = getchar()) == '-') f = -f;
    else x = x*10 + ch-'0';
    while((ch = getchar()) >= '0' && ch <= '9')
        x = x*10 + ch-'0';
    x *= f;
}
void _print(__int128 x)
{
    if(x > 9) _print(x/10);
    putchar(x%10 + '0');
}

int main()
{
	ios::sync_with_stdio(false);
	cin>>t;
	while(t--)
	{
		ans = 0;
		cin>>n;	
		for(int i=1;i<n;i++)
			cin>>a[i].u>>a[i].v>>a[i].w;
		sort(a+1,a+n,cmp);
		for(int i=1;i<=n;i++)
			pre[i] = i,val[i]=1;
		for(int i=1;i<n;i++)
		{
			int x = a[i].u;
			int y = a[i].v;
			int fx = find(a[i].u);
			int fy = find(a[i].v);
			ans += (__int128)val[fx] * val[fy] * a[i].w;
			val[fx] += val[fy];
			pre[fy] = fx;
		}
		_print(ans);
		putchar('\n');
	}
	return 0;
 } 

猜你喜欢

转载自blog.csdn.net/weixin_38772011/article/details/89644142