“玲珑杯”ACM比赛 Round #18 1147 - 最后你还是AK了(思维,边的贡献)

题目链接: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\n" :: "r"(p));
#else
    __asm__("movl %0, %%esp\n" :: "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\n" , ans);
    }
#ifdef OPENSTACK
    exit(0);
#else
    return 0;
#endif
}

 

posted @ 2017-07-17 09:35  Gealo  阅读(202)  评论(0编辑  收藏  举报