版权声明:本文为博主原创文章,未经博主允许不得转载。 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;
}