Educational Codeforces Round 52 (Rated for Div. 2) F. Up and Down the Tree 树型DP

题面

题意:给你一棵树,你起点在1,1也是根节点,你每次可以选择去你子树的某个叶子节点,也可以选择,从叶子节点返回距离不超过k的一个根,

         也就是说,你从1开始,向下跳,选择一个叶子(就是没有子树的节点),然后可以选择一个距离小于等于k的点跳回去,然后继续跳下去再跳上来,问你最多能去多少个叶子节点,n<=1e6

题解:大概分析就是要找一颗子树,然后叶子节点的到主链上的距离小于等于k的尽量多,这样我们就可以跳下跳上的跳很多次了

         h[u]表示u到最近的叶子节点的距离,f[u]表示u能去到最多叶子节点个数(f[1]也就是答案),a[u]表示如果从u跳下去又能跳回来的叶子节点个数

         大概描述我们的想法就是,对于每个点,我们先访问它的子树,自下而上,告诉他们,哪些叶子可以跳回来,对于每个点的答案就是,能跳回来的都跳,最后再跳下去不回来

         所以对于那些h[u]>=k 的u,a[u]=0,为什么有等号,其实这个a是对他的父亲节点起作用的,他的父亲需要他的a,而他需要的是他的儿子节点.

        代码上,学习了台湾人一波,inf的使用和f[v]和a[v]的先减后加使得代码更简洁ORz

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 1000006
 4 #define inf ((int)1e9)
 5 int nex[N],head[N],gox[N];
 6 int a[N],f[N],h[N],n,k,x,p;
 7 void build(int a,int b)
 8 {
 9     p++;
10     nex[p]=head[a];
11     gox[p]=b;
12     head[a]=p;
13 }
14 void dfs(int u)
15 {
16     h[u]=inf;
17     for (int e=head[u];e;e=nex[e])
18     {
19         int v=gox[e];
20         dfs(v);
21         h[u]=min(h[u],h[v]+1);
22         a[u]+=a[v]; 
23         f[u]=max(f[u],f[v]-a[v]);
24     }
25     f[u]+=a[u];
26     if (h[u]==inf) 
27     {
28         h[u]=0;
29         f[u]=a[u]=1;
30     }
31     if (h[u]>=k) a[u]=0;
32 }
33 
34 int main()
35 {
36     scanf("%d%d",&n,&k);
37     for(int i=2;i<=n;++i)
38     {
39         scanf("%d",&x);
40         build(x,i);
41     }
42     dfs(1);
43     printf("%d",f[1]);
44     return 0;
45 }

 

posted @ 2018-10-12 11:08  口香糖万岁  阅读(394)  评论(1编辑  收藏  举报