HDU 6060 RXD and dividing
真是哭了,今天多校的图论题,算得上是在比赛的时候的进阶题目,A了这道就能挤开一大片那种……
没A,思路错了……
题意:
给你一棵树,要你将 { 2,3,4……n } 进行划分成 k 个集合,每个集合与{ 1 }相并后 求 最小 斯坦纳树,求和的最大值。
思路:
考虑每条边贡献值,只可能是 k 与 子树结点的最小值,将贡献值与边长相乘累加后便是答案。原因yy即可。
一边dfs得出每个结点的子树结点数,复杂度 O ( n ) 。
AC Code
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 5;
int head[maxn];
int pre[maxn], num[maxn];
ll ans;
int n, idx, m;
struct node {
int to, weight, next;
} edges[maxn << 1];
void addEdge(int u, int v, int w)
{
edges[idx].to = v;
edges[idx].weight = w;
edges[idx].next = head[u];
head[u] = idx++;
}
void init()
{
for (int i = 0; i <= n; i++)
head[i] = -1;
idx = ans = 0;
}
int dfs(int u, int p)
{
num[u] = 1;
for (int id = head[u]; ~id; id = edges[id].next)
if (edges[id].to != p) {
pre[edges[id].to] = edges[id].weight;
num[u] += dfs(edges[id].to, u);
}
ans += min(num[u], m) * 1LL * pre[u];
return num[u];
}
int main()
{
int u, v, w;
while (scanf("%d %d", &n, &m) != EOF) {
init();
for (int i = 1; i < n; i++) {
scanf("%d %d %d", &u, &v, &w);
addEdge(u, v, w);
addEdge(v, u, w);
}
dfs(1, 0);
printf("%lld\n", ans);
}
return 0;
}