属于瞎推一推然后推着推着就能出的题。比较标准的 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;
}