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 }
Anderyi!