题面:
样例输入 Sample Input:
2
2
1 2
1
17 31
2
1 2
0
31 17
样例输出 Sample Output:
31 17
17 31
数据范围:
分析:
觉得这道题特别巧啊,考试的时候只考虑到了如果O(n)如何从a推b,从b推a简直无力。
我们假定以1为根,假设两个节点u,v,u与v之间有一条边相连。
从a推b:
b[u]=dis(1,u)*a[1]+dis(2,u)*a[2]+…+dis(n,u)*a[n];
b[v]=dis(1,v)*a[1]+dis(2,v)*a[2]+…+dis(n,v)*a[n];
所以不难得到:
b[v]-b[u]=(sum-siz[v])-siz[v]
//siz[v]表示v的子树的a的和,sum表示所有节点的a的和
因为对于v的子树,v到它们各点的距离比u小1,所以b[v]就比b[u]总共小siz[v],而对于子树外的点,则v到它们各点的距离比u大1,所以b[v]就比b[u]总共大sum-siz[v]
暴力求出b[1],再dfs一次求出每个节点
从b推a:
同样的定义sum和siz,
b[v]-b[u]=(sum-siz[v])-siz[v];
我们可以对于除根节点外的每一个节点都进行这样的相减,最后的和就可以得到
(n-1)sum-2(siz(1)+siz(2)+…+siz(n));
又因为b[1]=siz(2)+siz(3)+siz(4)+… +siz(n)
//这一步稍微反应下还是很容易的
//虽然我之前没想到
所以我们用上面得到的式子加2*b[1],就得到了(n-1)倍的sum,再将sum代入,利用dfs(由于叶节点的siz[v]=a[v],而非叶节点的a即sum-(子树中除它以外的a的和)),就可以得到a[i]了
没有什么很难的算法,但是很巧。。
code:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N = 1e5 + 10;
inline ll read(){
ll x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n;
struct node{int pre,v;} e[N<<1];
int num=0,head[N];
void addedge(int from,int to){
e[++num].pre=head[from],head[from]=num;
e[num].v=to;
}
int T;
ll a[N],b[N],sum=0;
#define ms(x,y) memset(x,y,sizeof(x))
void zero(){
ms(head,0);num=0;ms(b,0);ms(a,0);sum=0;
}
int dep[N];
ll sz[N];
void dfs_first1(int u,int f){
sz[u]=a[u];
for(int i=head[u];i;i=e[i].pre){
int v=e[i].v;
if(v==f) continue;
dep[v]=dep[u]+1;
dfs_first1(v,u);
sz[u]+=sz[v];
}
}
void dfs_first2(int u,int f){
for(int i=head[u];i;i=e[i].pre){
int v=e[i].v;
if(v==f) continue;
//int ans=query(1,1,n,in[v],out[v]);
b[v]=b[u]-sz[v]+sum-sz[v];
dfs_first2(v,u);
}
}
ll delta[N];
void dfs_second1(int u,int f){
for(int i=head[u];i;i=e[i].pre){
int v=e[i].v;
if(v==f) continue;
delta[v]=b[v]-b[u];
dfs_second1(v,u);
}
}
void dfs_second2(int u,int f){
for(int i=head[u];i;i=e[i].pre){
int v=e[i].v;
if(v==f) continue;
a[v]=(sum+b[u]-b[v])/2;
a[u]-=a[v];
dfs_second2(v,u);
}
}
int main(){
freopen("single.in","r",stdin);
freopen("single.out","w",stdout);
T=read();
while(T--){
zero();
n=read();
for(int i=1;i<n;i++){
int u=read(),v=read();
addedge(u,v);addedge(v,u);
}
int opt=read();
if(opt==0){
for(register int i=1;i<=n;i++) a[i]=read(),sum+=a[i];
dep[1]=0;
dfs_first1(1,0);
for(register int i=2;i<=n;i++) b[1]+=a[i]*dep[i];
dfs_first2(1,0);
for(register int i=1;i<=n;i++) printf("%lld ",b[i]);
printf("\n");
}
else{
for(register int i=1;i<=n;i++) b[i]=read();
dfs_second1(1,0);
for(register int i=2;i<=n;i++) sum+=delta[i];
sum+=2*b[1];sum/=(n-1);a[1]=sum;//printf("%d\n",sum);
dfs_second2(1,0);
for(register int i=1;i<=n;i++) printf("%lld ",a[i]);
printf("\n");
}
}
return 0;
}