题解: 我们可以得到
$ b[fa_i]+Sum-2*sz[i]=b[i] $
然后我们把n-1条边的价值求和起来化简
$ (n-1)*Sum-2*b[1]=\sum_{i=2}^{n}b[i]-b[fa_i] $
然后我们就能求得所有节点的$a[i]$的求和 然后做个树dp带入原始方程即可求得每个位置的$a[i]$
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <stack>
#include <queue>
#include <cmath>
#include <set>
#include <map>
#define mp make_pair
#define pb push_back
#define pii pair<int,int>
#define link(x) for(edge *j=h[x];j;j=j->next)
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,r,l) for(int i=r;i>=l;i--)
const int MAXN=3e5+10;
const double eps=1e-8;
#define ll long long
using namespace std;
struct edge{int t;edge*next;}e[MAXN<<1],*h[MAXN],*o=e;
void add(int x,int y){o->t=y;o->next=h[x];h[x]=o++;}
ll read(){
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return x*f;
}
ll b[MAXN],a[MAXN],c[MAXN];
ll sum,Sum;
void dfs(int x,int pre){
link(x){
if(j->t==pre)continue;
sum+=b[j->t]-b[x];
dfs(j->t,x);
}
}
void _dfs(int x,int pre){
link(x){
if(j->t==pre)continue;
_dfs(j->t,x);
c[x]+=c[j->t];
}
if(x!=1)a[x]=(Sum+b[pre]-b[x])/2-c[x],c[x]+=a[x];
}
int main(){
int n=read();
int x,y;
inc(i,2,n)x=read(),y=read(),add(x,y),add(y,x);
inc(i,1,n)b[i]=read();
sum=0;dfs(1,0);
Sum=(2*b[1]+sum)/(n-1);
_dfs(1,0);
a[1]=Sum-c[1];
inc(i,1,n)printf("%lld ",a[i]);
}
3727: PA2014 Final Zadanie
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 393 Solved: 175
[Submit][Status][Discuss]
Description
吉丽YY了一道神题,题面是这样的:
“一棵n个点的树,每条边长度为1,第i个结点居住着a[i]个人。假设在i结点举行会议,所有人都从原住址沿着最短路径来到i结点,行走的总路程为b[i]。输出所有b[i]。”
吉丽已经造好了数据,但熊孩子把输入文件中所有a[i]给删掉了。你能帮他恢复吗?
Input
第一行一个整数n(2<=n<=300000)。
接下来n-1行,每行两个整数x,y,表示x和y之间有连边。
接下来一行由空格隔开的n个整数b[i](0<=b[i]<=10^9)。
Output
输出一行由空格隔开的n个整数a[i]。
如果你觉得有多组解就任意输出其中一组。
Sample Input
2
1 2
17 31
1 2
17 31
Sample Output
31 17