The Experience of Love
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 645 Accepted Submission(s): 216
Please help them to calculate the sum of all experience of love after they have selected all cases.
For each test case the first line is a integer N, Then follows n−1 lines, each line contains three integers a, b, and c, indicating there is a edge connects city a and city b with distance c.
[Technical Specification]
1<N<=150000,1<=a,b<=n,1<=c<=109
3 1 2 1 2 3 2 5 1 2 2 2 3 5 2 4 7 3 5 4
Case #1: 1 Case #2: 17Hinthuge input,fast IO method is recommended. In the first sample: The maxValue is 1 and minValue is 1 when they select city 1 and city 2, the experience of love is 0. The maxValue is 2 and minValue is 2 when they select city 2 and city 3, the experience of love is 0. The maxValue is 2 and minValue is 1 when they select city 1 and city 3, the experience of love is 1. so the sum of all experience is 1;
题意:给一棵树,求任意{两点路径上的最大边权值-最小边权值}的总和。 解法:sigma(maxVal[i]−minVal[i])=sigma(maxVal)−sigma(minVal);所以我们分别求所有两点路径上的最大值的和,还有最小值的和。再相减就可以了。求最大值的和的方法用带权并查集,把边按权值从小到大排序,一条边一条边的算,当我们算第i条边的时候权值为wi,两点是ui,vi,前面加入的边权值一定是小于等于当前wi的,假设与ui连通的点有a个,与vi连通的点有b个,那么在a个中选一个,在b个中选一个,这两个点的路径上最大值一定是wi,一共有a∗b个选法,爱情经验值为a∗b∗wi。 求最小值的和的方法类似。 槽点: 一:这题做数据的时候突然想到的把数据范围设在 unsigned long long 范围内,要爆 long long,这样选手在wa了之后可能心态不好找不到这个槽点,当是锻炼大家的心态和出现wa时的找错能力了,把这放在pretest..很良心的。 二,并查集的时候,用是递归的需要扩栈,一般上10w的递归都需要,所以看见有几个FST在栈溢出的,好桑心。
注意此题要用无符号长整形= = 150000*75000*75000*1000000000会爆long long
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
#define N 200050
struct Edge
{
unsigned long long u,v,w;
}edge[N];
int n;
unsigned long long f[N],num[N];
unsigned long long maxn,minn;
bool cmp(Edge a,Edge b)
{
return a.w<b.w;
}
void init()
{
for(int i=1;i<=n;i++)
{
f[i]=i;
num[i]=1;
}
}
unsigned long long finds(unsigned long long x)
{
unsigned long long r=x;
while(f[r]!=r)
r=f[r];
while(f[x]!=x)
{
unsigned long long m=x;
x=f[x];
f[m]=r;
}
return r;
}
void Union(int id,int flag)
{
unsigned long long u=edge[id].u,v=edge[id].v,w=edge[id].w;
unsigned long long x=finds(u),y=finds(v);
if(flag) maxn+=num[x]*num[y]*w;
else minn+=num[x]*num[y]*w;
f[x]=y;
num[y]+=num[x];
}
int main()
{
int t=1;
while(~scanf("%d",&n))
{
for(int i=1;i<n;i++)
scanf("%I64u %I64u %I64u",&edge[i].u,&edge[i].v,&edge[i].w);
sort(edge+1,edge+n,cmp);
init();
maxn=0,minn=0;
for(int i=1;i<n;i++)
Union(i,1);
init();
for(int i=n-1;i>=1;i--)
Union(i,0);
printf("Case #%d: %I64u\n",t++,maxn-minn);
}
return 0;
}

针对一棵包含N个城市及N-1条边的树状结构,本算法探讨如何计算所有可能的城市对之间的路径上最大边权与最小边权之差的总和。采用带权并查集方法,对边进行排序,通过递归并查集找出每一对城市间的最大和最小边权。

被折叠的 条评论
为什么被折叠?



