題意:給定一棵無根樹,假設它有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
#includeusingnamespace
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個結點的距離和。通過觀察發現,只要我們找到了乙個點對應的結果,那麼其他所有的點都可以通過這個結果擴充套件出來,利用邊的關係。比如說,我們知道了第乙個結點對應的結果,並且...