1405 樹的距離之和 二次掃瞄換根法

2022-06-03 07:00:07 字數 1452 閱讀 2214

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

思路:開個陣列size記錄每個節點和它子節點集合的大小,開個sum用來記錄dfs過程中從根節點到子節點的距離,也就是距離字首和,f用來記錄每個節點到其他所有節點的距離。

2次dfs原因:

第一次:dfs我們可以從根節點向下求根節點到每個子節點的字首和,用sum記錄然後我們把每個節點的sum給了f[1]就求出根節點到所有節點的距離和了。同時回溯時,求出每個節點子集的大小,用size記錄。

第二次dfs:已知根節點1到其他節點的距離和,然後還已知每個節點子集的大小,該怎麼求其餘每個節點到其他節點的距離和?可以利用根的轉移。

對於遍歷到的任意乙個節點 i,對於與之相鄰的節點 j 來說,答案貢獻由 i 到 j 轉移首先減小了 siz

e[j]

∗1'>size[j]∗1

size[j]∗1,si

ze[j

]∗1'>同時增加了 (n−

size

[j])

∗1'>(n−size[j])∗1

(n−size[j])∗1,因此可以直接得到fdp[

j]=d

p[i]

+n−s

ize[

j]∗2

'>[j]=f[i]+n−size[j]∗2

f[j]=f[i]+n−size[j]∗2。

如圖,如果根轉移到節點2,距離首先要減少size[2]*1,然後要增加(n-size[2])*1,因為根變為節點2,節點一到節點二子集的所有距離要消失,也就是紅色部分(size[v]),要增加從節點2到節點一子集的距離也就是綠色部分(n-size[v]),得狀態轉移方程如下:

f[v]=f[u]+n-size[v]*2

#includeusing

namespace

std;

#define ll long long

const

int maxn=1e5+10

;int head[2*maxn],ver[2*maxn],nxt[2*maxn];

int tot=0

;int

n;ll sum[maxn],size[maxn],f[maxn];

void add(int u,int

v)void dfs1(int u,int

fa)}

void dfs2(int u,int

fa)}

intmain()

dfs1(

1,0);

dfs2(

1,0);

for(int i=1; i<=n; i++)

printf(

"%lld\n

",f[i]);

}

1405 樹的距離之和

1405 樹的距離之和 基準時間限制 1 秒 空間限制 131072 kb 給定一棵無根樹,假設它有n個節點,節點編號從1到n,求任意兩點之間的距離 最短路徑 之和。input 第一行包含乙個正整數n n 100000 表示節點個數。後面 n 1 行,每行兩個整數表示樹的邊。output 每行乙個整...

51nod 1405 樹的距離之和

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

51Nod 1405 樹的距離之和

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