Luo Gu [P2986] great gathering cows

Description

Given a large tree nodes bit right, while the right side there is obtained a point ANS, so that the minimum cost, wherein $ cost = \ sum \ limits_ {i = 1} ^ {n} {val [i] * dis (ans, i)} $

Solution

Tree dp

Still resolved through twice dfs

The core idea is "second to scan and change root Act" (the term comes from lyd "algorithm contest Step-up Guide")

We assume that dfs is the root and the first pass is determined ans when positioned at the expense of a DIS

There is clearly $ dis [i] = \ sum \ limits_ {j \ in son (i)} {dis [j] + len (i, j) * tot [j]} $, wherein TOT [j] represents a j is a right subtree rooted at a node point, and

So we dfs then again to achieve "change root"

Suppose the current node i, and i father had calculated correctly, we remember the price ans located at his father as $ f [fa] $, we consider how by $ f [fa] $ find $ f [i] $

$ F [fa] $ comprising two parts: i consideration in the subtree rooted and the rest. So we first $ f [fa] $ i is minus the cost of sub-tree root, and then add the subtree rooted at i went i costs, plus the cost of the remainder of the i's to come

See detailed implementation code.

Time complexity is $ O (n) $

Code

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int maxn = 100010;
 5 inline int read() {
 6     int ret = 0, op = 1;
 7     char c = getchar();
 8     while (!isdigit(c)) {
 9         if (c == '-') op = -1; 
10         c = getchar();
11     }
12     while (isdigit(c)) {
13         ret = ret * 10 + c - '0';
14         c = getchar();
15     }
16     return ret * op;
17 }
18 struct node {
19     int nxt, to, dis;
20 } a[maxn << 1];
21 int num, head[maxn], n, val[maxn];
22 ll tot[maxn], dis[maxn], f[maxn];
23 ll sum;
24 inline void add(int from, int to, int dis) {
25     a[++num].nxt = head[from];
26     a[num].to = to;
27     a[num].dis = dis;
28     head[from] = num;
29 }
30 ll dfs(int now, int fa) {
31     for (register int i = head[now]; i; i = a[i].nxt) {
32         int to = a[i].to;
33         if (to == fa) continue ;
34         ll ret = dfs(to, now);
35         dis[now] += dis[to] + a[i].dis * ret;
36         tot[now] += ret;
37     } 
38     return tot[now] = tot[now] + val[now];
39 }
40 void dp(int now, int fa) {
41     for (register int i = head[now]; i; i = a[i].nxt) {
42         int to = a[i].to;
43         if (to == fa) continue ;
44         f[to] = (f[now] - (dis[to] + a[i].dis * tot[to])) + (a[i].dis * (sum - tot[to])) + dis[to];
45         dp(to, now);
46     }
47 }
48 int main() {
49     n = read();
50     for (register int i = 1; i <= n; ++i) val[i] = read(), sum += val[i];
51     for (register int i = 1; i < n; ++i) {
52         int x = read(), y = read(), z = read();
53         add(x, y, z); add(y, x, z);
54     }
55     dfs(1, 1);
56     f[1] = dis[1];
57     dp(1, 1);
58     ll ans = 9223372036854775806ll;
59     for (register int i = 1; i <= n; ++i) ans = min(ans, f[i]);
60     printf("%lld\n", ans);
61     return 0;
62 }
AC Code

 

Guess you like

Origin www.cnblogs.com/shl-blog/p/11333167.html