10
13
2015
0

3727: PA2014 Final Zadanie

3727: PA2014 Final Zadanie

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 137  Solved: 61
[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

HINT

 

Source

    这道题真的是太神了。。。

    刚开始看到有多组解以为是构造可行解。。然后在那里想贪心什么的可不可以做。。然后突然发现这题没有SPJ。。。。 出题人你这坑挖的有点大啊。。

    后来实在想不出去看了PoPoQQQ的blog。。。感觉实在是太神了、。、、

    我们可以先想怎么通过a[i]计算b[i]。。

    这个可以用树形DP做。。设1为根.dis[x]为x到根的距离.size[x]为以x为根的子树的权值和。。\[b[1] = \Sigma a[i]*dis[i]\]\[b[x] = b[fa[x]]-size[x]+(size[1]-size[x])\]\[=b[fa[x]]-2*size[x]+size[1]\]所以可以得到\[2*size[x]=b[fa[x]]-b[x]+size[1]\]显然的\[a[x] = size[x]-\Sigma a[son[x]]\]

    因为我们知道了所有的b[i]。所以我么可以根据\(2*size[x]=b[fa[x]]-b[x]+size[1]\)求出\(2*size[i]-size[1]=b[fa[i]]-b[i]\)。。我们把这个设为doublesize

    然后根据\(a[x] = size[x]-\Sigma a[son[x]]\)可以类似的求出\(doublea[i] = doublesize[i]-\Sigma doublesize[x](x为i的儿子节点)\)

    但是我们求出的这些值中都带有size[1]。。所以我们要把这些消掉。。因为我们知道\(b[1] = \Sigma a[i]*dis[i]\)我们同理合并所有的doublea得到doubleb1然后因为b[1]已知所以我们可以求出size[1]的值。。然后就可以把所有doublea中的size[1]去掉求出a[i]。。。然后一切就完美地解决了。。。

#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;
const ll N = 300010;
struct data{ll first,second;} double_a[N],double_size[N],b_1;
struct node{ll x,y,next;} e[N<<1];
ll head[N],b[N],a[N],n,cnt,x,y,ans,h,t,q[N],dis[N],fa[N];
ll read(){
	ll x = 0,f = 1,c = getchar();
	while (c<'0' || c>'9') {if (c=='-') f = -1;c = getchar();}
	while (c>='0' && c<='9') x = x*10+c-'0',c = getchar();
	return x*f;
}
void Insert(ll x,ll y){
	e[++cnt].x = x;e[cnt].y = y;
	e[cnt].next = head[x];head[x] = cnt;
}
void operator -= (data &a,data b){a.first-=b.first;a.second-=b.second;}
void operator += (data &a,data b){a.first+=b.first;a.second+=b.second;}
data operator * (data a,ll b){return (data){a.first*b,a.second*b};}
void Bfs(){
	q[1] = 1;h = 0;t = 1;
	while (h<t){
		ll x = q[++h];
		for (ll i=head[x];i;i=e[i].next)
			if (e[i].y !=fa[x]){
				fa[e[i].y] = x;
				dis[e[i].y] = dis[x]+1;
				q[++t] = e[i].y;
			}
	}
}
int main(){
	n = read();
	for (ll i=1;i<n;i++){
		x = read();y = read();
		Insert(x,y);Insert(y,x);
	}
	for (ll i=1;i<=n;i++) b[i] = read();
	Bfs();
	for (ll i=2;i<=n;i++) double_size[i] = (data){1,b[fa[i]]-b[i]};
	for (ll x=2;x<=n;x++){
		double_a[x] = double_size[x];
		for (ll i=head[x];i;i=e[i].next)
			if (e[i].y!=fa[x]) double_a[x]-=double_size[e[i].y];
		b_1+=double_a[x]*dis[x];
	}
	ans = a[1] = (2*b[1]-b_1.second)/b_1.first;
	for (ll i=2;i<=n;i++){a[i] = (double_a[i].second+double_a[i].first*ans)/2;a[1]-=a[i];}
	for (ll i=1;i<n;i++) printf("%lld ",a[i]);printf("%lld\n",a[n]);
}
Category: BZOJ题解 | Tags: | Read Count: 721

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com