题面
分析
不妨看看, b [ f a [ x ] ] − b [ x ] b[fa[x]]-b[x] b[fa[x]]−b[x] 等于什么,手算一下,发现是 x x x 子树的总人数 - 不为 x x x 子树成员的总人数。(这个性质还是很容易发现的。)
然后我想的是(如果你只想看正解,后四排可跳过。)
令 c [ x ] = b [ f a [ x ] ] − b [ x ] c[x]=b[fa[x]]-b[x] c[x]=b[fa[x]]−b[x]。令 x x x 为现在的结点, s o n son son 为其儿子, u p up up 为它上面的一堆元素。
则 ∑ c [ s o n ] = − ( s i z e s o n − 1 ) × s u m s o n − s i z s o n × ( x + u p ) \sum c[son]=-(sizeson-1)\times sumson-sizson\times (x+up) ∑c[son]=−(sizeson−1)×sumson−sizson×(x+up)
又 c [ x ] = s u m s o n + x − u p c[x]=sumson+x-up c[x]=sumson+x−up
你会发现,做到这里,有三个变量,两个方程,做不了。
考虑算出所有结点的人数和。
令 s u m sum sum 为所有节点的人数和, z s [ x ] zs[x] zs[x] 为子树的人数和。
好,又看到这个式子: b [ f a [ x ] ] − b [ x ] b[fa[x]]-b[x] b[fa[x]]−b[x] = x x x 子树的总人数 - 不为 x x x 子树成员的总人数。
我们不妨换个写法,用带有 s u m sum sum 的式子表达。
b [ f a [ x ] ] − b [ x ] = 2 z s [ x ] − s u m b[fa[x]]-b[x]=2zs[x]-sum b[fa[x]]−b[x]=2zs[x]−sum
所以 ∑ b [ f a [ x ] ] − b [ x ] = ∑ 2 z s [ x ] − ( n − 1 ) × s u m \sum {b[fa[x]]-b[x]}=\sum 2zs[x]-(n-1)\times sum ∑b[fa[x]]−b[x]=∑2zs[x]−(n−1)×sum
ps:这里是核心,也是难点,妙的在于它巧妙地利用了原本的条件。
考虑把 z s [ x ] zs[x] zs[x] 约去,这里有个很巧妙的处理,我也是看了题解才明白的。。。(我太菜了)
对于一个树上的一个节点 x x x,它对 ∑ z s [ i ] \sum zs[i] ∑zs[i] 的贡献为它到 1 1 1 的距离,则 ∑ z s [ i ] \sum zs[i] ∑zs[i] 刚好为 b [ 1 ] b[1] b[1]。
所以 ∑ b [ f a [ x ] ] − b [ x ] = 2 × b [ 1 ] − ( n − 1 ) × s u m ( x ! = 1 ) \sum {b[fa[x]]-b[x]}=2\times b[1]-(n-1)\times sum\ \ \ \ (x!=1) ∑b[fa[x]]−b[x]=2×b[1]−(n−1)×sum (x!=1)
这样就可以算出 s u m sum sum。
算出这个后,我们就可以知道 x x x 子树的总人数 + 不为 x x x 子树成员的总人数,与 b b b 数组联立,即可算出子树和。
a
n
s
[
x
]
=
z
s
[
x
]
−
∑
z
s
[
s
o
n
[
x
]
]
(
x
!
=
1
)
ans[x]=zs[x]-\sum zs[son[x]]\ \ \ \ (x!=1)
ans[x]=zs[x]−∑zs[son[x]] (x!=1)。
a
n
s
[
1
]
=
s
u
m
−
∑
a
n
s
[
i
]
(
i
!
=
1
)
ans[1]=sum-\sum ans[i]\ \ \ \ (i!=1)
ans[1]=sum−∑ans[i] (i!=1)
Code
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <vector>
#define LL long long
using namespace std;
const int MAXN = 3e5 + 5;
int n, b[MAXN], a[MAXN];
LL sum_, ans[MAXN], zs[MAXN];
vector <int> v[MAXN];
void dfs(int x, int fa) {
if(~fa) sum_ += b[fa] - b[x];
for(unsigned int i = 0; i < v[x].size(); i ++) {
int Y = v[x][i]; if(Y == fa) continue; dfs(Y, x);
}
}
int dfs1(int x, int fa) {
if(~fa) zs[x] = (b[fa] - b[x] + sum_) / 2;
LL tmp = 0;
for(unsigned int i = 0; i < v[x].size(); i ++) {
int Y = v[x][i]; if(Y == fa) continue;
tmp += dfs1(Y, x);
}
ans[x] = zs[x] - tmp;
return zs[x];
}
int main() {
int x, y;
scanf("%d", &n);
for(int i = 1; i < n; i ++) scanf("%d%d", &x, &y), v[x].push_back(y), v[y].push_back(x);
for(int i = 1; i <= n; i ++) scanf("%d", &b[i]);
dfs(1, -1); sum_ = (b[1] * 2 - sum_) / (n - 1); dfs1(1, -1); ans[1] = sum_;
for(int i = 2; i <= n; i ++) ans[1] -= ans[i];
for(int i = 1; i <= n; i ++) printf("%lld ", ans[i]);
return 0;
}