[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 MB
Submit: 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

Sample Output

31 17
posted @ 2019-03-01 18:56  wang9897  阅读(244)  评论(0编辑  收藏  举报