codeforces 802K Send the Fool Further! (medium) 树形dp

K. Send the Fool Further! (medium)
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Thank you for helping Heidi! It is now the second of April, but she has been summoned by Jenny again. The pranks do not seem to end...

In the meantime, Heidi has decided that she does not trust her friends anymore. Not too much, anyway. Her relative lack of trust is manifested as follows: whereas previously she would not be made to visit the same person twice, now she can only be sure that she will not be made to visit the same person more than k times. (In the case of Jenny, this includes her first visit in the beginning. The situation from the easy version corresponds to setting k = 1.)

This is not as bad as it looks, since a single ticket for a route between two friends allows Heidi to travel between this pair of friends the whole day (in both directions). In other words, once she pays for travel between a pair of friends, all further travels between that pair are free.

How much money will Heidi waste now, in a worst-case scenario?

Input

The first line contains two space-separated integers – the number of friends n () and the parameter k (1 ≤ k ≤ 105). The next n - 1 lines each contain three space-separated integers uv and c (0 ≤ u, v ≤ n - 11 ≤ c ≤ 104) meaning that u and v are friends and the cost for traveling between u and v is c.

It is again guaranteed that the social network of the input forms a tree.

Output

Again, output a single integer – the maximum sum of costs of tickets.

Examples
input
9 3
0 1 1
0 2 1
1 3 2
1 4 2
1 5 2
2 6 3
2 7 3
2 8 3
output
15
input
9 5
0 1 1
0 2 1
1 3 2
1 4 2
1 5 2
2 6 3
2 7 3
2 8 3
output
17
input
11 6
1 0 7932
2 1 1952
3 2 2227
4 0 9112
5 4 6067
6 0 6786
7 6 3883
8 4 7137
9 1 2796
10 5 6200
output
54092
Note

In the first example, the worst-case scenario for Heidi is to visit the friends in the following order: 0, 1, 5, 1, 3, 1, 0, 2, 6, 2, 7, 2, 8. Observe that no friend is visited more than 3 times.


题目大概意思是这样的。。是给定一棵树,每条边上有一个宝物价值为w,每个节点最多访问k次,求能得到的最大价值
dp[u][1]表示访问完以u为根的子树并且返回到u的父节点fa所得到的最大价值
dp[u][0]表示访问完以u为根的子树并且不返回到u的父节点fa而是停在这棵子树内部所得到的最大价值

#include <cstdio>
#include <vector>
#include <algorithm>
#include <utility>
#include <cstring>

using namespace std;
const int maxn = 1e5 + 10;
int N, K;
int cnt, head[maxn], dp[maxn][2];

struct E
{
	int v, w, next;
}G[maxn * 2];

void add(int u, int v, int w)
{
	G[cnt].v = v;
	G[cnt].w = w;
	G[cnt].next = head[u];
	head[u] = cnt++;
}

void dfs(int u, int p, int last)
{
	dp[u][0] += last;
	dp[u][1] += last;
	vector< pair<int, int> > tmp;
	for (int i = head[u]; i != -1; i = G[i].next)
	{
		int v = G[i].v;
		int w = G[i].w;
		if (v == p) continue;
		dfs(v, u, w);
		tmp.push_back(make_pair(dp[v][1], v));
	}
	sort(tmp.begin(), tmp.end());
	reverse(tmp.begin(), tmp.end());

	int ans = 0;
	int max_tmp = 0;
	for (int i = 0; i < K - 1 && i < tmp.size(); i++) {
		dp[u][1] += tmp[i].first;
	} 
	for (int i = 0; i < K && i < tmp.size(); i++) ans = ans + tmp[i].first;
	for (int i = 0; i < tmp.size(); i++)
	{
		if (i < K)
			max_tmp = max(max_tmp, ans - tmp[i].first + dp[tmp[i].second][0]);
		else
			max_tmp = max(max_tmp, ans - tmp[K - 1].first + dp[tmp[i].second][0]);
	}
	dp[u][0] += max_tmp;
}

int main()
{
	cnt = 0;
	memset(head, -1, sizeof(head));
	memset(dp, 0, sizeof(dp));
	scanf("%d%d", &N, &K);
	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);
	}
	dfs(0, -1, 0);
	printf("%d\n", dp[0][0]);

	return 0;
}


引用\[1\]中提到了一种树形动态规划的方法来解决CodeForces - 982C问题。在这个问题中,subtree指的是子连通块,而不是子树。为了使cnt_white - cnt_black尽可能大,可以使用两次树形动态规划来求解。第一次是自底向上的过程,维护一个dp数组,表示以每个节点为根的子树中的最大连通块。第二次是自顶向下的过程,处理自底向上过程中无法包含的树链所代表的子树。在第二次遍历中,需要维护一个sum变量,用于存储树链所代表的子树的贡献。根据ans\[u\]的正负,决定是否能对相邻的子节点做出贡献。如果ans\[u\]为正,则减去dp\[v\]就是树链所代表的子树的权值。最终,ans\[u\]代表包含节点u在内的子连通块的最大权值。\[1\] 问题: CodeForces - 982C 树形DP是什么问题?如何解决? 回答: CodeForces - 982C是一个树形动态规划问题。在这个问题中,需要求解子连通块的最大权值和,使得cnt_white - cnt_black尽可能大。解决这个问题的方法是使用两次树形动态规划。第一次是自底向上的过程,维护一个dp数组,表示以每个节点为根的子树中的最大连通块。第二次是自顶向下的过程,处理自底向上过程中无法包含的树链所代表的子树。在第二次遍历中,需要维护一个sum变量,用于存储树链所代表的子树的贡献。根据ans\[u\]的正负,决定是否能对相邻的子节点做出贡献。最终,ans\[u\]代表包含节点u在内的子连通块的最大权值。\[1\] #### 引用[.reference_title] - *1* *2* [CodeForces - 1324F Maximum White Subtree(树形dp)](https://blog.csdn.net/qq_45458915/article/details/104831678)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值