任務( \(task\) )
Description
沒頭腦是一家大公司的 \(CEO\) 。該公司由 \(N\) 人組成,編號為 \(1\) 到 \(N\) ,沒頭腦編號為 \(1\) 。每個員工(沒頭腦除外)都有一個老板,我們說這個員工是該老板的助手。每個老板都可以有多名助手。沒頭腦沒有老板,但有他的助手。
之后會有一些任務,沒頭腦會將該任務委托給他編號最小的助手。然后,該助手也將任務委托給他編號最小的助手,並且這個過程重復進行,直到任務被發送給沒有助手的人,然后他必須親自完成任務。
執行任務的人獲得 \(1\) 個硬幣,那個人的老板獲得 \(2\) 個硬幣,老板的老板獲得 \(3\) 個硬幣,依此類推,一直到沒頭腦。之后,真正完成工作的員工意識到系統的不公平並感到傷心,並且不會再執行任務(也就是辭職)。
當公司收到的下一個任務時,因為少了一個人,所以薪水可能更少,但工作必須繼續。任務是無限多的(直到公司倒閉),因此整個過程(分配新任務,執行任務,划分薪水和執行任務人員的退出)重復進行,最后沒頭腦獨自留在公司並完成他的第一個(也是他的最后一個)任務。
當然,在此之前,沒頭腦將積累相當多的財富,但他也想知道每個員工賺了多少錢。
Input
第一行有一個整數 \(N\) ,包括沒頭腦在內的員工的個數。
第二行有 \(N-1\) 個整數,分別為 \(a_2,a_3,⋯,a_N\) ,依次表示編號 \(2,3,4,..N\) 的員工的老板。
Output
輸出一行 \(N\) 個整數,第 \(i\) 個整數表示編號為 \(i\) 的人獲得的硬幣數量。
Sample Input
【樣例1輸入】
3
1 1
【樣例2輸入】
5
1 2 2 4
Sample Output
【樣例1輸出】
5 1 1
【樣例2輸出】
13 8 1 3 1
HINT
對於 \(50 \%\) 的數據,\(2<=N<=5000\)。
對於 \(100\%\) 的數據,\(2<=N<=2\times10^5\)。
題目大意
給出一棵有 \(N\) 個結點的樹。從每一個葉子結點開始,它到根結點路徑上的結點貢獻依次增加 \(1\), 然后刪除遍歷到的葉子結點。重復以上過程,直到樹中的結點全部被刪除為止。(每刪除一個結點,其父親結點便會成為葉子結點)
解題思路
設每個結點的最終貢獻為 \(f_i\) 。
顯然,初始每個結點的貢獻都為 \(1\),即 \(f_i=1\) 。
假設結點 \(u\),有一子結點 \(v\),由一個葉子 \(o\) 結點到 \(v\) 的貢獻為 \(k\),則 \(o\) 到 \(u\) 的貢獻為 \(k+1\),可得出 \(f_u=f_v+siz_v\) 。
由此,可得出樹上轉移方程:$$f_u=\sum\limits_{v\in son_u}f_v+siz_v$$
AC CODE
#include<bits/stdc++.h>
#define int long long
#define _ (int)3e5 + 5
using namespace std;
int n;
int head[_], to[_ << 1], nxt[_ << 1], tot;
int siz[_];
int ans[_];
void add(int a, int b)
{
to[++tot] = b;
nxt[tot] = head[a];
head[a] = tot;
}
void dfs(int now)
{
siz[now] = 1;
ans[now] = 1;
for(int i = head[now]; i; i = nxt[i])
{
int v = to[i];
dfs(v);
siz[now] += siz[v];
ans[now] += ans[v] + siz[v];
}
}
signed main()
{
scanf("%lld", &n);
for(int i = 2; i <= n; ++i)
{
int a;
scanf("%lld", &a);
add(a, i);
}
dfs(1);
for(int i = 1; i <= n; ++i) printf("%lld ", ans[i]);
return 0;
}