列表

详情


NC20908. 金币

描述

给定一个森林,森林中的每棵树上的每个点都有一枚金币。悲惨的是,每个点最多只能容纳一枚金币。如果一个点有偶数枚金币,所有的金币都会消失。如果一个点有奇数枚金币,则只会留下一枚金币。
由于重力作用,每秒钟所有点上的金币都会向下移动 1 个单位(即到它的父亲节点处)。假设您目前在树根的位置观看金币下落,请问您最后能在每棵树的树根处捡到最多的金币,捡到的金币枚数是多少?

输入描述

第一行一个整数 n(2≤n≤106)。表示森林中的点的个数。
第二行包含一个由 n 个数组成的序列(每个数保证在 0 到 n 之间)。序列中的第 i 个数表示第 i 个点的父亲。特别地,当数列中的一个数 pi=0时,则说明它是森林中某一棵树的根。

输出描述

一行若干个整数,表示在每棵树的树根处能捡到的金币枚数(请按输入顺序输出每一个树根的答案,即若有很多棵树,请按输入的顺序依次输出每一个树根的答案)。

示例1

输入:

18
0 1 1 1 4 4 3 2 2 2 10 8 9 9 9 10 10 4

输出:

4

说明:

下图所示为样例中树的初始形态。

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 164ms, 内存消耗: 8288K, 提交时间: 2019-11-22 22:25:10

#include<bits/stdc++.h>
using namespace std;

int H,brother[1000005],son[1000005],D[1000005];
vector<int>R;
void dfs(int x,int h)
{
	H=max(H,h);
	D[h]++;
	if(brother[x])dfs(brother[x],h);
	if(son[x])dfs(son[x],h+1);
	return;
}
int main()
{
	int i,j,s,n;
	scanf("%d",&n);
	for(i=1;i<=n;i++)
	{
		scanf("%d",&j);
		brother[i]=son[j];
		if(j)son[j]=i;
		else R.push_back(i); 
	}
	for(i=0;i<R.size();i++)
	{
		H=s=0,dfs(R[i],1);
		for(j=1;j<=H;j++)s+=(D[j]&1),D[j]=0;
		if(i)printf(" ");
		printf("%d",s);
	}
	printf("\n");
	return 0;
}

C++ 解法, 执行用时: 118ms, 内存消耗: 16024K, 提交时间: 2022-06-04 15:44:21

#include<cstdio>
using namespace std;
int k,n,ans,y;
int fa[1000005],h[1000005],b[1000005];
struct AB{
	int e,n;
}a[1000005];
void add(int u,int v){
	a[++k].e=v,a[k].n=h[u],h[u]=k;
}
void dfs(int x,int d){
	b[d]^=1;
	if(b[d] == 1) ++ans;
	else --ans;
	if(d > y) y=d;
	for(int i=h[x];i;i=a[i].n){
		dfs(a[i].e,d+1);
	}
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&fa[i]);
		add(fa[i],i);
	}
	for(int i=1;i<=n;i++){
		ans=0;
		if(!fa[i]) dfs(i,++y),printf("%d ",ans);	
	}
	return 0;
}

上一题