本題屬於二和一問題 子問題相互對稱
考慮對於問題一:知a求b
那麼根據b陣列定義式 顯然能發現問題在於如何求dis(最短路)
有很多演算法可供選擇 dijsktra,floyed,bfs/dfs,spfa等
然而我們發現本題一個特點為邊權相等(1) 顯然應用dfs/bfs演算法時間複雜度優於傳統求最短路演算法
考慮對於問題二:知b求a
同樣,我們能很快明確高斯消元演算法並且也需要計算dis陣列
然而 觀察資料範圍 T<=5, 2<=n<=100000,1<=u,v<=n
顯然這道題正解並不是高斯消元與最短路演算法 因為空間與時間複雜度完全不可能(將dis陣列轉為一維 對於問題一能解決dis陣列空間限制 然而對於其餘關鍵演算法無能為力)
那麼在考場上正確的策略顯然是對暴力求法進行優化而不是一味追求正解 順著這個思路繼續思考
考慮對於問題一:
演算法瓶頸在於求解最短路的時間空間問題 分析資料範圍我們發現至少複雜度要降低一個維度才可行
這啟發我們利用遞推方式求解 加之以本題是樹形結構 思路就逐漸明瞭:二次掃描與換根法(對於NOIP模擬級習題 本演算法顯然不必多講)
那麼思維方向已現 考慮節點轉移對於b陣列的影響可推出 b[node[i].to] = b[from] + sum_w - w[node[i].to] * 2(其中w[i]代表已i為跟節點子樹sigma(a))依次優化複雜度
考慮對於問題二:
儘管高斯消元不可行 但問題本質仍然為對b[i]的求解 也就是說同樣需要消元求解
問題一的解法啟發我們問題二應該也與樹形結構有關
類比問題一 我們考慮節點轉移對a陣列的影響很容易得出 b[node[i].to] - b[from] = sum_w - w[node[i].to] * 2;
至此我們推出了將b[2]~b[n]與w[2]~w[n]聯絡在一起的式子 很容易想到要求b[1]與這些量之間的關係 易得 b[1] = sigma(w[i]) (i!=1)
顯然連線紐帶在於w陣列 初等變換得 sigma(b[node[i].to - b[from]) = (n - 1)*sum_w - 2*sigma(w[i]) 代入b[1]得 sigma(b[node[i],to - b[from]]) + 2*b[1] = (n - 1)*sum_w;
代入求得sum_w 在將sum_w代回原式可解出w[i]
根據w[i]的定義 可知求解a陣列只需要對w陣列做差分即可
程式碼如下(主要是思路 程式碼無難度 建議練習)

1 #include<bits/stdc++.h>
2 using namespace std;
3 #define I int
4 #define LL long long
5 #define B bool
6 #define C char
7 #define RE register
8 #define V void
9 #define L inline
10
11 const I MAXN = 100010;
12 I T,t,x,y,n;
13 LL a[MAXN],b[MAXN],sum[MAXN];
14 I num,head[MAXN];
15 LL SUM;
16 B jud[MAXN];
17 struct LYM
18 {
19 I to,next;
20 }node[MAXN << 1];
21 L I read(); L V store(I,I);
22 V dfs1(I); V dfs2(I); V dfs3(I); V dfs4(I);
23 signed main()
24 {
25 T = read();
26 while(T -- ){
27 n = read();
28 for(RE I i(1);i < n; ++ i){
29 x = read(),y = read();
30 store(x,y),store(y,x);
31 }
32 t = read();
33 if(t)
34 {
35 for(RE I i(1);i <= n; ++ i) b[i] = read();
36 dfs3(1); SUM += b[1] * 2; SUM /= n - 1;
37 sum[1] = SUM; dfs4(1);
38 for(RE I i(1);i <= n; ++ i) printf("%lld ",a[i]);
39 }
40 else
41 {
42 for(RE I i(1);i <= n; ++ i) a[i] = read();
43 dfs1(1);
44 for(RE I i(2);i <= n; ++ i) b[1] += sum[i];
45 dfs2(1);
46 for(RE I i(1);i <= n; ++ i) printf("%lld ",b[i]);
47 }
48 printf("\n");
49 num = 0,SUM = 0;
50 memset(head,0,sizeof(head));
51 memset(sum,0,sizeof(sum));
52 memset(a,0,sizeof(a));
53 memset(b,0,sizeof(b));
54 }
55 }
56 L I read()
57 {
58 RE I x(0),y(1); RE C z = getchar();
59 while(!isdigit(z)) y |= z == '-',z = getchar();
60 while(isdigit(z)) x = (x << 3) + (x << 1) + (z ^ 48),z = getchar();
61 return x * y;
62 }
63 L V store(I from,I to)
64 {
65 node[++num].to = to;
66 node[num].next = head[from];
67 head[from] = num;
68 }
69 V dfs1(I from){
70 jud[from] = 1;
71 sum[from] += a[from];
72 for(RE I i(head[from]); i ;i = node[i].next){
73 if(!jud[node[i].to]){
74 dfs1(node[i].to);
75 sum[from] += sum[node[i].to];
76 }
77 }
78 jud[from] = 0;
79 }
80 V dfs2(I from){
81 jud[from] = 1;
82 for(RE I i(head[from]); i ;i = node[i].next){
83 if(!jud[node[i].to]){
84 b[node[i].to] = b[from] + sum[1] - (sum[node[i].to] << 1);
85 dfs2(node[i].to);
86 }
87 }
88 jud[from] = 0;
89 }
90 V dfs3(I from){
91 jud[from] = 1;
92 for(RE I i(head[from]); i ;i = node[i].next){
93 if(!jud[node[i].to]){
94 SUM += b[node[i].to] - b[from];
95 dfs3(node[i].to);
96 }
97 }
98 jud[from] = 0;
99 }
100 V dfs4(I from){
101 jud[from] = 1;
102 LL tool = sum[from];
103 for(RE I i(head[from]); i ;i = node[i].next){
104 if(!jud[node[i].to]){
105 sum[node[i].to] = (SUM - b[node[i].to] + b[from]) >> 1;
106 dfs4(node[i].to);
107 tool -= sum[node[i].to];
108 }
109 }
110 a[from] = tool;
111 jud[from] = 0;
112 }