解题报告:P8347 Accumulation Degree

题意

给定一棵 nn 个节点的无根树(n2×105n \le 2 \times 10 ^ 5),每一条树上的边有一个流量,你需要选取一个点为根(源点),所有叶子节点为汇点,使得树中的最大流量最大(到达所有汇点的流量之和最大)

思路

由于本题没有指定树根,可以考虑换根 dp

首先假设节点 1 为根,求出每个节点到其子树的最大流量 did_i(当 ii 无儿子时 di=0d_i = 0),记以 uu 为根时的最大流量为 dpudp_u,那么显然有 dp1=d1dp_1 = d_1

考虑转移

假设我们已经求出了 dpudp_{u} ,且 uu 存在一个儿子 vv,那么当以 vv 为根时其流量会分为两部分,一部分是 vv 到其子树的流量,一部分是 vv 通过 vvuu 的边流向其他地方的流量

那么显然 vv 到其子树的流量为 dvd_v,而 vv 通过 vvuu 的边流向其他地方的流量为 dpudp_u 减去 vvdpudp_u 做出的贡献

此处要注意 uu 的度数为 11 的情况,vv 的度数为 11 的情况并分类讨论

则有如下转移方程

dpv=dv+{c(u,v),(duu=1)min(c(u,v),dpumin(dv,c(u,v))),(duu1)dp_v = d_v + \begin{cases} c(u, v), & (du_u = 1) \\ \min(c(u, v), dp_u - \min(d_v, c(u, v))), & (du_u \not = 1) \end{cases}

其中,duidu_i 表示节点 ii 的度数

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include <bits/stdc++.h>
namespace solution
{
typedef long long LL;
const int MAXN = 2e5 + 5;
const int INF = 0x3f3f3f3f;
int t;
int n;
int ans = 0;
struct Edge
{
int from, to, cap;
Edge(int _from, int _to, int _cap) : from(_from), to(_to), cap(_cap) {}
};
std::vector<Edge> edge;
std::vector<int> g[MAXN];
void insert(int u, int v, int c)
{
g[u].push_back(edge.size());
edge.push_back(Edge(u, v, c));
}
int d[MAXN], dp[MAXN];
int dfs(int u, int fa)
{
for (auto &i : g[u])
{
auto &e = edge[i];
if (e.to == fa)
{
continue;
}
d[u] += std::min(dfs(e.to, u) == 0 ? INF : d[e.to], e.cap);
}
return d[u];
}
void solve(int u, int fa)
{
ans = std::max(ans, dp[u]);
for (auto &i : g[u])
{
auto &e = edge[i];
if (e.to == fa)
{
continue;
}
dp[e.to] = d[e.to] + std::min(e.cap, dp[u] - std::min((d[e.to] == 0 ? INF : d[e.to]), e.cap));
solve(e.to, u);
}
}
void init()
{
ans = 0;
edge.clear();
for (int u = 1; u <= n; u++)
{
dp[u] = d[u] = 0, g[u].clear();
}
}
int main()
{
scanf("%d", &t);
while (t--)
{
init();
scanf("%d", &n);
for (int i = 1; i < n; i++)
{
int u, v, c;
scanf("%d %d %d", &u, &v, &c);
insert(u, v, c), insert(v, u, c);
}
dp[1] = dfs(1, 0), solve(1, 0);
printf("%d\n", ans);
}
return 0;
}
}
int main()
{
solution::main();
return 0;
}