属于瞎推一推然后推着推着就能出的题。比较标准的 CF Div2 D 难度。
钦定 为根,下文设
表示子树
的
值和。
对于 ,我们有
,这是一个自然的拆贡献。
对于每一个非根节点 (即
)和它的父亲
,我们有
。你考虑
相比
多了一个子树外的和,少了一个子树内的和就容易得到。显然这样的柿子有
个。
将这 个柿子加起来,我们又得到了
。
都是已知的,所以我们就知道了
,进而推出所有
。推出了所有
后也就容易推出所有
,这里非常显然。
code
#include <bits/stdc++.h>
//taskkill /f /im Untitled1.exe
#define ED cerr<<endl;
#define TS cerr<<"I AK IOI"<<endl;
#define cr(x) cerr<<x<<endl;
#define cr2(x,y) cerr<<x<<" "<<y<<endl;
#define cr3(x,y,z) cerr<<x<<" "<<y<<" "<<z<<endl;
#define cr4(x,y,z,w) cerr<<x<<" "<<y<<" "<<z<<" "<<w<<endl;
#define all(s) s.begin(),s.end()
#define pii pair<int,int>
#define epb emplace_back
#define pb push_back
#define mk make_pair
#define ins insert
#define fi first
#define se second
#define ll long long
//#define ull unsigned long long
using namespace std;
const int N=6e5+5,mod=998244353;
const ll INF=1e18;
int n,m,s,t;
vector<int> e[N];
ll sm[N],_ans[N],ans[N],qwq=0,s1=0,sum=0;
void dfs(int u,int fa) {
if(u!=1) qwq+=sm[u]-sm[fa];
for(auto to:e[u]) {
if(to==fa) continue;
dfs(to,u);
}
}
void dfs2(int u,int fa) {
if(u!=1) {
_ans[u]=ans[u]=(s1-(sm[u]-sm[fa]))/2;
}
else _ans[u]=ans[u]=s1;
for(auto to:e[u]) {
if(to==fa) continue;
dfs2(to,u);
ans[u]-=_ans[to];
}
}
int main() {
scanf("%d",&n);
int u,v;
for(int i=1;i<=n-1;++i) {
scanf("%d%d",&u,&v);
e[u].epb(v),e[v].epb(u);
}
for(int i=1;i<=n;++i) {
scanf("%lld",&sm[i]);
}
dfs(1,-1);
s1=(sm[1]*2+qwq)/(n-1);
dfs2(1,-1);
for(int i=1;i<=n;++i) {
printf("%lld ",ans[i]);
}
puts("");
return 0;
}