RXD and dividing

来源:互联网 发布:dsdt for mac 编辑:程序博客网 时间:2024/06/05 05:54

HDU 6060
这里写图片描述

给定一棵树,节点2..n划分成k个集合,求所有({1} U Si)的最小生成树的路径和。
一开始想着如何划分,后来想一想算每条边的贡献比较简单,以1为跟dfs一次计算每棵子树的大小,如果子树比k大,那么这条边的贡献为 x*k, 否则为 x*f[i],(f[i]为子树大小,x为边权)。因为一颗子树下的点分配到至多k个集合,每次贡献不会超过k次。

#include <bits/stdc++.h>#include <vector>using namespace std;const int maxn = 1000010;int n, m, a[maxn], num, x, y, z, f[maxn];bool flag[maxn];long long ans;struct Node {    int v, t;    Node() {}    Node(int vv, int tt): v(vv), t(tt) {}};vector<Node> G[maxn];void prepare(int x) {    f[x] = 1;    flag[x] = false;    for (int i = 0; i < G[x].size(); i++) if (flag[G[x][i].v]) {        prepare(G[x][i].v);        f[x] += f[G[x][i].v];    }}void dfs(int x) {    flag[x] = false;    for (int i = 0; i < G[x].size(); i++) if (flag[G[x][i].v]) {        /*if (x == 1) ans += 1LL*f[G[x][i].v]*G[x][i].t;        else */ans += 1LL*min(f[G[x][i].v], m)*G[x][i].t;        dfs(G[x][i].v);    }}int main() {    //freopen("input.txt","r",stdin);    while (scanf("%d %d", &n, &m) != EOF) {        for (int i = 1; i <= n; i++) G[i].clear();        memset(f, 0, sizeof(f));        num = 0;        ans = 0;        a[0] = 0;        for (int i = 1; i < n; i++) {            scanf("%d %d %d", &x, &y, &z);            G[x].push_back(Node(y, z));            G[y].push_back(Node(x, z));        }        memset(flag, true, sizeof(flag));        prepare(1);        memset(flag, true, sizeof(flag));        dfs(1);        //m-num        //for (int i = 1; i <= m-num; i++) if (i <= a[0]) ans -= a[i];        printf("%lld\n", ans);    } }
原创粉丝点击