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;
}