1. 程式人生 > 實用技巧 >晚間測試3 B. 單(single)

晚間測試3 B. 單(single)

題目描述

單車聯通大街小巷.這就是出題人沒有寫題目背景的原因.
對於一棵樹,認為每條邊長度為 \(1\),每個點有一個權值\(a[i]\).\(dis(u,v)\)為點\(u\)\(v\)的最短路徑的邊數.\(dis(u,u)=0\).對每個點求出一個重要程度.點\(x\)的重要程度\(b[x]\)定義為其他點到這個點的距離乘上對應的點權再求和. 即:\(b[x]=a[1]*dis(1,x)+a[2]*dis(2,x)+....+a[n]*dis(n,x)\)
現在有很多樹和對應的\(a\)陣列,並求出了\(b\)陣列.不幸的是,記錄變得模糊不清了.幸運的是,樹的形態完好地儲存了下來,\(a\)

陣列和\(b\)陣列至少有一個是完好無損的,但另一個數組完全看不清了.
希望你求出受損的陣列.多組資料.

輸入格式

第一行輸入一個\(T\),表示資料組數。接下來\(T\)組資料。
每組資料的第\(1\)\(1\)個整數\(n\)表示樹的點數.節點從\(1\)\(n\)編號.
接下來\(n-1\)行每行兩個整數\(u,v\)表示\(u\)\(v\)之間有一條邊.
接下來一行一個整數\(t\),表示接下來陣列的型別。
\(t=0\)則下一行是\(a\)陣列,\(t=1\)則下一行是\(b\)陣列。
接下來一行\(n\)個整數,表示儲存完好的那個陣列,第\(i\)個數表示\(a[i]\)\(b[i]\)

輸出格式

\(T\)行,每組資料輸出一行表示對應的\(a\)陣列或\(b\)陣列,陣列的相鄰元素用一個空格隔開。忽略行末空格和行尾回車.

樣例

樣例輸入

2
2
1 2
1
17 31
2
1 2
0
31 17

樣例輸出

31 17
17 31

資料範圍與提示

對於\(100\%\)的資料,\(T=5,2<=n<=100000,1<=u,v<=n\),保證給出的\(n-1\)條邊形成一棵樹
對於\(100\%\)的資料,\(t=0\)\(t=1,1<=a[i]<=100,1<=b[i]<=10^9\)\(t=1\)時保證給出的\(b\)陣列對應唯一的一個\(a\)

陣列。
對於\(100\%\)的資料,單個輸入檔案不會包含超過\(2000000\)個整數,這段話可以理解為,你不必考慮輸入輸出對程式執行時間的影響。
對於\(100\%\)的資料,保證答案不會超過\(int\)能表示的範圍
接下來的表格中描述了每個測試點的具體特徵。每個測試點的\(5\)組資料均符合表格中對應的特徵。

分析

預設 \(1\) 號節點為根節點
我們設 \(sum[i]\) 為以 \(i\) 為根的子樹中 \(a\) 陣列的和
\(t=0\) 時,顯然是一個換根 \(DP\),有 \(b[now]=b[fa]+sum[1]-sum[now]-sum[now]\)
\(t \neq 0\) 時,如果資料範圍較小的話可以進行高斯消元
但是這道題的 \(n\) 比較大,所以我們只能推式子
由換根 \(DP\) 的式子,我們可以得到對於除\(1\)之外的任何節點都有 \(b[now]-b[fa]=sum[1]-2sum[now]\)
我們把這些式子相加,可以得到 \(x_1b[1]+x_2b[2]+...+x_nb[n]=(n-1)sum[1]-2 \sum_{i=2}^nsum[now]\)
對於左邊這一堆,我們可以 \(dfs\) 求出每一個節點對應的係數 \(x_i\),從而得到左邊的值
對於右邊的 \(\sum_{i=2}^nsum[now]\),其實就是 \(b[1]\)
因為我們在換根 \(DP\) 的第一個 \(dfs\) 時會有 \(b[1]= \sum_{u=son\ of\ 1}sum[u]+g[u]\)
其中 \(g[u]=\sum_{v=son\ of\ u}sum[v]+g[v]\)
當遞迴到葉子節點時,會有\(g[u]=sum[u]=a[u]\)
所以\(\sum_{i=2}^nsum[now]=b[1]\)
我們帶入上面的式子就可以求出 \(sum[1]\)
進行一遍 \(dfs\) 可以求出所有節點的\(sum\)
再進行一遍 \(dfs\) 就可以求出所有節點的\(a\)

程式碼

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#define int long long
inline int read(){
	int x=0,fh=1;
	char ch=getchar();
	while(ch<'0' || ch>'9'){
		if(ch=='-') fh=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9'){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*fh;
}
const int maxn=1e6+5;
int n,head[maxn],tot=1,t;
struct asd{
	int to,next;
}b[maxn];
void ad(int aa,int bb){
	b[tot].to=bb;
	b[tot].next=head[aa];
	head[aa]=tot++;
}
void clr(){
	memset(head,-1,sizeof(head));
	memset(&b,0,sizeof(b));
	tot=1;
}
int zd[maxn];
int f[maxn],g[maxn],siz[maxn],sum;
void dfs1(int now,int fa){
	siz[now]=zd[now];
	for(int i=head[now];i!=-1;i=b[i].next){
		int u=b[i].to;
		if(u==fa) continue;
		dfs1(u,now);
		g[now]+=g[u]+siz[u];
		siz[now]+=siz[u];
	}
}
void dfs2(int now,int fa){
	if(now==1){
		f[now]=g[now];
	}
	for(int i=head[now];i!=-1;i=b[i].next){
		int u=b[i].to;
		if(u==fa) continue;
		f[u]=f[now]+sum-siz[u]-siz[u];
		dfs2(u,now);
	}
}
void solve1(){
	memset(siz,0,sizeof(siz));
	memset(f,0,sizeof(f));
	memset(g,0,sizeof(g));
	sum=0;
	for(int i=1;i<=n;i++){
		sum+=zd[i];
	}
	dfs1(1,0);
	dfs2(1,0);
	for(int i=1;i<=n;i++){
		printf("%lld ",f[i]);
	}
	printf("\n");
}
int nans,ncnt,xs[maxn];
void dfs3(int now,int fa){
	for(int i=head[now];i!=-1;i=b[i].next){
		int u=b[i].to;
		if(u==fa) continue;
		dfs3(u,now);
		xs[u]++;
		xs[now]--;
	}
}
void dfs4(int now,int fa){
	for(int i=head[now];i!=-1;i=b[i].next){
		int u=b[i].to;
		if(u==fa) continue;
		siz[u]=(siz[1]+zd[now]-zd[u])/2;
		dfs4(u,now);
	}
}
void dfs5(int now,int fa){
	for(int i=head[now];i!=-1;i=b[i].next){
		int u=b[i].to;
		if(u==fa) continue;
		siz[now]-=siz[u];
		dfs5(u,now);
	}
}
void solve2(){
	memset(siz,0,sizeof(siz));
	memset(xs,0,sizeof(xs));
	dfs3(1,0);
	nans=0;
	for(int i=1;i<=n;i++){
		nans+=(1LL*zd[i]*xs[i]);
	}
	siz[1]=nans-ncnt*zd[1];
	siz[1]+=2*zd[1];
	siz[1]/=(n-1);
	dfs4(1,0);
	dfs5(1,0);
	for(int i=1;i<=n;i++){
		printf("%lld ",siz[i]);
	}
	printf("\n");
}
signed main(){
	freopen("single.in","r",stdin);
	freopen("single.out","w",stdout);
	t=read();
	while(t--){
		clr();
		n=read();
		int aa,bb,op;
		for(int i=1;i<n;i++){
			aa=read(),bb=read();
			ad(aa,bb);
			ad(bb,aa);
		}
		op=read();
		for(int i=1;i<=n;i++){
			zd[i]=read();
		}
		if(op==0){
			solve1();
		} else {
			solve2();
		}
	}
	return 0;
}