题目链接:http://www.ifrog.cc/acm/problem/1147
题解:这题很容易想到的是边的贡献也就是每条边最多被取到几次,和点的贡献类似,那些加边只要加在边贡献大的边上就行。然后什么是边的贡献,就是一条边左右两边连着的最小的点的个数,因为这条边最多被取到这么多次。还有就是爆栈的处理具体看一下代码那个define的就是爆栈的处理如果是lunix的话那个else不需要。
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <cstdlib> #include <cstring> #include <cassert> #define inf 0X3f3f3f3f #define OPENSTACK using namespace std; const int M = 1e5 + 10; typedef long long ll; struct TnT { int v , next , w; }edge[M << 1]; struct GBA { ll val , pos; int num; }GG[M]; int e , head[M] , n , k , in[M] , cnt; ll c[M]; bool cmp(GBA x , GBA y) { return x.num > y.num; } void init() { e = 0, cnt = 0; memset(head , -1 , sizeof(head)); memset(in , 0 , sizeof(in)); } void add(int u , int v , int w) { edge[e].v = v; edge[e].w = w; edge[e].next = head[u]; head[u] = e++; } ll dfs(int u , int pre) { ll sum = 1; for(int i = head[u] ; i != -1 ; i = edge[i].next) { int v = edge[i].v; if(v == pre) continue; ll ans = dfs(v , u); GG[cnt].num = min(ans , (ll)n - ans), GG[cnt++].val = edge[i].w; sum += ans; } return sum; } int main() { #ifdef OPENSTACK int size = 64 << 20; // 64MB char *p = (char*)malloc(size) + size; #if (defined _WIN64) or (defined __unix) __asm__("movq %0, %%rsp " :: "r"(p)); #else __asm__("movl %0, %%esp " :: "r"(p)); #endif #endif int t; scanf("%d" , &t); while(t--) { scanf("%d%d" , &n , &k); init(); for(int i = 1 ; i < n ; i++) { int u , v , w; scanf("%d%d%d" , &u , &v , &w); add(u , v , w); add(v , u , w); in[u]++, in[v]++; } for(int i = 0 ; i < k ; i++) scanf("%lld" , &c[i]); for(int i = 1 ; i <= n ; i++) { if(in[i] == 1) { dfs(i , -1); break; } } sort(GG , GG + n , cmp); sort(c , c + k); reverse(c , c + k); ll ans = 0; for(int i = 0 ; i < k ; i++) { ans += GG[i].num * (GG[i].val + c[i]); } for(int i = k ; i < cnt ; i++) ans += GG[i].num * GG[i].val; printf("%lld " , ans); } #ifdef OPENSTACK exit(0); #else return 0; #endif }