hdu5176 树上所有两点间(最大值-最小值)和
这是民大学长之前出的一次题目,感觉题目不错现在才写题解=
化简不难得到: sig(maxval[i]−minval[i])=sig(maxval)−sigma(minval)
如何求所有最大值和最小值呢,分别从大到小和从小到大排序利用并查集就行了,比较巧妙。
额==题目设了一些坑,一个是一个方向的并查集会爆栈,故手工开栈,另外一个是钥匙用unsigned long long==
1 #pragma comment(linker,"/STACK:16777216") 2 #include<stdio.h> 3 #include<string.h> 4 #include<algorithm> 5 using namespace std; 6 #define LL long long 7 #define uLL unsigned long long 8 struct dian{ 9 uLL x,y,w; 10 }a[150005]; 11 uLL father[150005],num[150005],n; 12 int cmp1(dian n1,dian n2) 13 { 14 return n1.w<n2.w; 15 } 16 int cmp2(dian n1,dian n2) 17 { 18 return n1.w>n2.w; 19 } 20 uLL find(uLL x) 21 { 22 if (x!=father[x]) father[x]=find(father[x]); 23 return father[x]; 24 } 25 uLL work() 26 { 27 uLL ans=0,i,f1,f2; 28 for (i=1;i<=n;i++) 29 { 30 father[i]=i; 31 num[i]=1; 32 } 33 for (i=1;i<n;i++) 34 { 35 f1=find(a[i].x); f2=find(a[i].y); 36 ans+=num[f1]*num[f2]*a[i].w; 37 father[f1]=f2; 38 num[f2]+=num[f1]; 39 } 40 return ans; 41 } 42 int main() 43 { 44 uLL t=0,ans1,ans2,i; 45 while (~scanf("%I64u",&n)) 46 { 47 for (i=1;i<n;i++) 48 scanf("%I64u%I64u%I64u",&a[i].x,&a[i].y,&a[i].w); 49 sort(a+1,a+n,cmp1); 50 ans1=work(); 51 sort(a+1,a+n,cmp2); 52 ans2=work(); 53 printf("Case #%I64u: %I64u\n",++t,ans1-ans2); 54 } 55 return 0; 56 }