51nod 1405 樹的距離之和

2021-07-11 15:57:35 字數 1432 閱讀 8253

給定一棵無根樹,假設它有n個節點,節點編號從1到n, 求任意兩點之間的距離(最短路徑)之和。

input

第一行包含乙個正整數n (n <= 100000),表示節點個數。

後面(n - 1)行,每行兩個整數表示樹的邊。

output

每行乙個整數,第i(i = 1,2,...n)行表示所有節點到第i個點的距離之和。
input示例

4

1 23 2

4 2

output示例

535

5

官方題解:
數學題,也可以說dp,不太難。

(1)我們給樹規定乙個根。假設所有節點編號是0-(n-1),我們可以簡單地把0當作根,這樣下來父子關係就確定了。

(2)定義陣列num[x]表示以節點x為根的子樹有多少個節點,dp[x]是我們所求的——所有節點到節點x的距離之和。

(3)在步驟(1)中,其實我們同時可以計算出 num[x],還可以計算出每個節點的深度(每個到根節點0的距離),累加全部節點深度得到的其實就是是dp[0]。

(4) 假設乙個非根節點x,它的父親節點是y, 並且dp[y]已經計算好了,我們如何計算dp[x]?  

以x為根的子樹中那些節點,到x的距離比到y的距離少1, 這樣的節點有num[x]個。

其餘節點到x的距離比到y的距離多1,這樣的節點有(n - num[x])個。

於是我們有 dp[x] = dp[y] - num[x] + (n - num[x])

= dp[y] + n - num[x] * 2

因為樹的根節點dp[0]在步驟(3)已經計算出來了,根據所有的父子關係和這個上式,我們可以按照順序計算出整個dp陣列。

注意點: 重要的步驟都是簡單的dfs,但是一半遞迴實現可能導致堆疊溢位。

#include#include#include#include#include#include#include#include#pragma comment(linker, "/stack:10240000,10240000")

using namespace std;

typedef long long ll;

const int inf =0x3f3f3f3f;

const double pi = acos(-1.0);

const int n = 1e5 + 10;

int root[n], num[n], len[n], vis[n], n;

vectorpath[n];

ll dp[n];

void dfs1(int x)

{ num[x] = 1;

for(int i = 0, sz = (int)path[x].size(); i

曹鵬(題目提供者)

51Nod 1405 樹的距離之和

acm模版 根據題意,這是一顆樹,所以每兩點之間的路徑一定是唯一的。這裡讓求所有點到第i個結點的距離和,其實也就是其他所有結點到第i個結點的距離和。通過觀察發現,只要我們找到了乙個點對應的結果,那麼其他所有的點都可以通過這個結果擴充套件出來,利用邊的關係。比如說,我們知道了第乙個結點對應的結果,並且...

51nod 1405 樹的距離之和

給定一棵無根樹,假設它有n個節點,節點編號從1到n,求任意兩點之間的距離 最短路徑 之和。input 第一行包含乙個正整數n n 100000 表示節點個數。後面 n 1 行,每行兩個整數表示樹的邊。output 每行乙個整數,第i i 1,2,n 行表示所有節點到第i個點的距離之和。input示例...

51nod 1405 樹的距離之和

思路 可以先隨便選取節點1作為樹的根節點,然後從根節點遍歷樹,每次儲存k節點的子節點總數 d k s 以及所有子節點都k節點的距離和 d k sum,在遍歷過程就可完成儲存。然後再從根節點遍歷一遍樹,求所有點到k節點的距離,就可以轉換成求k節點的子節點到k節點的距離s1和k節點的頭節點id其所在的另...