任务(task)


任务( \(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;
}


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM