CodeForces 1065F Up and Down the Tree(BFS+DFS)

Up and Down the Tree

time limit per test:3 seconds
memory limit per test:256 megabytes
Problem Description

You are given a tree with n vertices; its root is vertex 1. Also there is a token, initially placed in the root. You can move the token to other vertices. Let’s assume current vertex of token is v, then you make any of the following two possible moves:

  • move down to any leaf in subtree of v;
  • if vertex v is a leaf, then move up to the parent no more than k times. In other words, if h(v) is the depth of vertex v (the depth of the root is 0), then you can move to vertex to such that to is an ancestor of v and h(v)kh(to).
    Consider that root is not a leaf (even if its degree is 1). Calculate the maximum number of different leaves you can visit during one sequence of moves.
Input

The first line contains two integers n and k (1≤k<n≤106) — the number of vertices in the tree and the restriction on moving up, respectively.

The second line contains n1 integers p2,p3,…,pn, where pi is the parent of vertex i.

It is guaranteed that the input represents a valid tree, rooted at 1.

Output

Print one integer — the maximum possible number of different leaves you can visit.

Sample Input

7 1
1 1 3 3 4 4

Sample Output

4

题意

有一棵树,1号节点为根节点,有一个人,可以按照以下规则移动

  • 从当前节点进入其子树下的任一叶节点,
  • 如果当前是叶节点,可以向上走不超过k步
    初始在根节点,问最多能到达多少个不同的叶节点
题解:

对于一个叶节点,假如处于当前节点,一定是尽可能的往上退的,因为那样才能有机会访问更多的叶节点。所以设数组num,num[i]代表从当前节点走能访问到的叶子节点并最高回到i号节点的叶子数量。对于每个叶节点,求出它按照规则走,能到达的最高的节点。为什么不直接说向上走k步,因为存在叶子节点较深,向上走几步,然后到一个深度较小的叶子节点,然后在向上退k步的情况。这样能到达比直接向上k步更靠近根节点的点。
对于num数组,深度优先进行bfs,求每个节点对应的num。首先将叶节点放入队列中,然后先访问深度较大的节点,如果可以继续向上走,则将当前节点的num加给其父节点, 同时每个节点维护走到当前节点最多能再向上走几步的信息。
最后再从根节点dfs一下,求向下的路径中最大的num和饥渴。

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<ctype.h>
#include<cstring>
#include<vector>
#include<queue>
#include<map>
#include<iostream>
#include<iterator>
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
#define eps 1e-8
 
using namespace std;
typedef long long LL;
typedef pair<int, int> P;
const int maxn = 1000100;
const int mod = 772002;
struct node{
	int u, dep;
	node(){}
	node(int a, int b):u(a), dep(b){}
	bool operator <(node b)const
	{
		return dep < b.dep;
	}
};
//num:最多能回到i号节点的叶子节点的数量
//b:当前节点最多能向上走几步
int ans, num[maxn], fa[maxn], b[maxn], dep[maxn], vis[maxn];
vector<int> g[maxn];
void bfs(int n, int k);
void dfs(int u, int de, int num1);

int main()
{
	int n, k, i, j;
	scanf("%d %d", &n, &k);
	for(i=2;i<=n;i++){
		scanf("%d", &fa[i]);
		g[fa[i]].push_back(i);
	}
	//dfs求深度
	dfs(1, 1, 0);
	ans = 0;
	//bfs求每个点最多能到几个叶子节点并回到当前节点
	bfs(n, k);
	//dfs求最优解
	dfs(1, 1, num[1]);
	printf("%d\n", ans);
	return 0;
}

void dfs(int u, int de, int num1)
{
	ans = max(num1, ans);
	dep[u] = de;
	for(int i=0;i<g[u].size();i++)
		dfs(g[u][i], de+1, num1 + num[g[u][i]]);
}

void bfs(int n, int k)
{
	int i, j;
	memset(vis, 0, sizeof(vis));
	priority_queue<node> que;
	for(int i=1;i<=n;i++){
		if(!g[i].size()){
			que.push(node(i, dep[i]));
			b[i] = k;
			num[i] = 1;
		}
	}
	//深度优先bfs
	while(!que.empty())
	{
		node p = que.top();que.pop();
		if(b[p.u] == 0 || p.u == 1 || vis[p.u])continue;
		vis[p.u] = 1;
		b[fa[p.u]] = max(b[p.u]-1, b[fa[p.u]]);
		num[fa[p.u]] += num[p.u];
		que.push(node(fa[p.u], dep[fa[p.u]]));
		//为避免重复计数,将当前节点的数量清0
		num[p.u] = 0;
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值