题解 AT2044 【[AGC004D] Teleporter】

ez_lcw

2020-11-03 18:37:32

Solution

先不看 $1$ 号点连出去的那条边,那么剩下来的就是一棵内向树。 对于这棵树来说,发现那些与 $1$ 号点的距离小于 $k$ 的点来说,他们肯定需要一条 $1$ 号点的自环来满足条件,否则肯定有一些点无论怎么改都到达不了 $1$ 号点。 得到了这个结论,剩下的就很好搞了,我们从下往上贪心:一旦遇到以当前点 $u$ 为根的子树的最深的未被满足的点到自己的距离等于 $k-1$,我们就可以让 $u$ 向 $1$ 连一条边,然后这棵子树的点都能被满足。 至于过程一遍 $\texttt{dfs}$ 就好了,然后也有一些细节,详见代码: ```cpp #include<bits/stdc++.h> #define N 100010 using namespace std; int n,k,ans,a[N]; int cnt,head[N],nxt[N],to[N]; void adde(int u,int v) { to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; } int dfs(int u,int dep) { int maxdep=dep;//维护以点 $u$ 为根的子树的最深的未被满足的点的深度 for(int i=head[u];i;i=nxt[i]) { int v=to[i]; maxdep=max(maxdep,dfs(v,dep+1)); } if(maxdep-dep==k-1)//如果最深点到当前点的距离为k { if(a[u]!=1)//注意如果原来有了连向1的边就不用统计进ans了 { a[u]=1; ans++; } return dep-1; } return maxdep; } int main() { scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); if(i!=1) adde(a[i],i); } dfs(1,1); if(a[1]!=1) ans++;//1号点自环 printf("%d\n",ans); return 0; } /* 6 2 2 1 1 3 3 4 */ ```