[BZOJ]3727: PA2014 Final Zadanie
题解: 我们可以得到
$ 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