题意:一个叫Gorwin的女孩和一个叫Vivin的男孩是一对情侣。他们来到一个叫爱情的国家,这个国家由N个城市组成而且只有N−1条小道(像一棵树),每条小道有一个值表示两个城市间的距离。他们选择两个城市住下,Gorwin在一个城市Vivin在另外一个,第一次约会,Gorwin去找Vivin,她会写下路径上最长的一条小道(maxValue),第二次约会,Vivin去找Gorwin,他会写下路径上最短的一条小道(minValue),然后计算maxValue减去minValue的结果作为爱情经验值,再然后重新选择两个城市居住而且计算新的爱情经验值,重复一次又一次。当他们选择过所有的情况后,请帮助他们计算一下爱情经验值的总和。
分析: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。求最小值的和的方法类似。
#include <cstdio> #include <cstring> #include <string> #include <cmath> #include <limits.h> #include <iostream> #include <algorithm> #include <queue> #include <cstdlib> #include <stack> #include <vector> #include <set> #include <map> #define LL long long #define mod 100000000 #define inf 0x3f3f3f3f #define eps 1e-6 #define N 200010 #define FILL(a,b) (memset(a,b,sizeof(a))) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define PII pair<int,int> #pragma comment(linker,"/STACK:1024000000,1024000000") using namespace std; int num[N],fa[N],n; inline int read() { int x=0; char ch=getchar(); while(ch<'0'||ch>'9'){ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x; } struct edge { int u,v,w; }e[N]; int cmp1(edge a,edge b) { return a.w<b.w; } int cmp2(edge a,edge b) { return a.w>b.w; } void init() { for(int i=1;i<=n;i++)fa[i]=i,num[i]=1; } int find(int x) { return fa[x]==x?x:fa[x]=find(fa[x]); } int main() { int cas=1; while(scanf("%d",&n)>0) { for(int i=1;i<n;i++) { e[i].u=read(); e[i].v=read(); e[i].w=read(); } init();sort(e+1,e+n,cmp1); unsigned long long maxsum=0,t=1; for(int i=1;i<n;i++) { int pa=find(e[i].u); int pb=find(e[i].v); if(pa==pb)continue; maxsum+=t*num[pa]*num[pb]*e[i].w; fa[pa]=pb; num[pb]+=num[pa]; } unsigned long long minsum=0; init();sort(e+1,e+n,cmp2); for(int i=1;i<n;i++) { int pa=find(e[i].u); int pb=find(e[i].v); if(pa==pb)continue; minsum+=t*num[pa]*num[pb]*e[i].w; fa[pa]=pb; num[pb]+=num[pa]; } printf("Case #%d: ",cas++); cout<<maxsum-minsum<<endl; } }