Final Zadanie 题解

题意

给出一棵树,求一组 \(a_i\), 满足:

\[\Large \operatorname{dist(1,1)}\times a_1+\operatorname{dist(1,2)}\times a_2+\dots\operatorname{dist(1,n)}\times a_n=b_1\\\Large \operatorname{dist(2,1)}\times a_1+\operatorname{dist(2,2)}\times a_2+\dots\operatorname{dist(2,n)}\times a_n=b_2\\\Large \vdots\\\Large \operatorname{dist(n,1)}\times a_1+\operatorname{dist(n,2)}\times a_2+\dots\operatorname{dist(n,n)}\times a_n=b_n \]


题解

考虑算贡献 ?

\(f_i\) 表示第 \(i\) 个结点子树的 \(a\) 和。

\(g_i\) 表示第 \(i\) \(\dots\) \(f\)

\(\Large f_1-2 \times f_i=b_i-b_{fa_i}\)

上面这个式子直接用图形理解应该会方便一点。

此外,

\(\Large b_1=g_1-f_1=\sum\limits_{i=1}^n f_i-f_1=\sum\limits_{i=2}^n f_i\)

所以

\(\Large 2\times b_1=2\times \sum\limits_{i=2}^nf_i\dots①\)

因此

\[\Large \sum_{i=1}^n f_1-2 \times f_i = \sum_{i=1}^n b_i-b_{fa_i} \]

\[\Large n\times f_1-\sum_{i=1}^n 2\times f_i=\sum b_i-\sum b_{fa_i} \]

则:

\[\Large \sum_{i=2}^n(b_i-b_{fa_i})=(n-1)\times f_1-\sum_{i=2}^n2\times f_i \dots ② \]

所以:

\[\Large ①+②:\sum_{i=2}^n(b_i-b_{fa_i})+2\times b_1=(n-1)\times f_1 \]

得到了:

\[\Large f_1=\dfrac{2\times b_1+\sum\limits_{i=2}^n(b_i-b_{fa_i})}{n-1} \]

那么结合

\[\Large f_1-2 \times f_i=b_i-b_{fa_i} \]

,就可以求到每一个 \(f_i\) 了,然后再搜一遍得到 \(a_i\) 即可。


代码

#include <cstdio>
#include <vector>
#include <algorithm>
#define ll long long
using namespace std;
vector <int> G[300005];
ll a[300005],f[300005],b[300005];
ll sum=0;
void dfs(int u,int fa,int op)
{
	if(op==1&&fa) sum+=b[u]-b[fa];
	else if(op==2&&fa) f[u]=(f[1]-b[u]+b[fa])/2,a[u]=f[u];
	else if(op==2&&!fa) a[u]=f[1];
	for(int i=0;i<G[u].size();i++)
	{
		int v=G[u][i];
		if(v==fa) continue;
		dfs(v,u,op);
		if(op==2) a[u]-=f[v];
	}
}
int main() {
	int n;
	scanf("%d",&n);
	for(int i=1,u,v;i<n;i++)
	{
		scanf("%d %d",&u,&v);
		G[u].push_back(v);
		G[v].push_back(u);
	}
	for(int i=1;i<=n;i++) scanf("%lld",&b[i]);
	sum+=2ll*b[1];
	dfs(1,0,1);
	f[1]=sum/(n-1);
	dfs(1,0,2);
	for(int i=1;i<=n;i++) printf("%lld ",a[i]);
	return 0;
}
posted @ 2020-11-02 22:08  Azazеl  阅读(79)  评论(0编辑  收藏  举报