[agc004D]Teleporter

时间:2023-03-09 15:21:59
[agc004D]Teleporter

Description

传送门

Solution

依题意我们可以知道,以2-n为出发点的边和1号节点会构成一课树(不然2-n号节点无法都达到首都)。

为了让2-n号节点中,离1号节点的距离<k的能够使到1号点到路径长为k(>k的先不讨论),我们需要1号节点的边指向自己。(否则1号节点会和某些点组成一个环,由于环的大小>1,距离<k的点只能不断给路径长度加上环的大小,总是会有这样的点路径长不能等于k)

至于>k的点,我们就考虑贪心强拆,从下往上贪心。如果当前处理到了一棵深度=k-1的子树(设子树根节点深度1)则需要把这棵子树拆出来(其实是让子树根节点出发的边指向首都),当然根节点要特判。

其实贪心也可以从上往下。但是从下往上才能够得到最优解。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
int n,k,a[],dep[],maxn[],ans;
struct node{int y,nxt;
}g[];int h[];
void dfs(int x)
{
for (int i=h[x];i;i=g[i].nxt)
if (g[i].y!=x)
{
dep[g[i].y]=dep[x]+;
dfs(g[i].y);
maxn[x]=max(maxn[x],maxn[g[i].y]);
}
maxn[x]=max(maxn[x],dep[x]);
if (x==) return;
if (maxn[x]-dep[x]>=k-&&a[x]!=||(maxn[x]-dep[x]>=k)) maxn[x]=,ans++;
}
int main()
{
scanf("%d%d",&n,&k);
scanf("%d",&a[]);
for (int i=;i<=n;i++)
{
scanf("%d",&a[i]);
g[i]=node{i,h[a[i]]};h[a[i]]=i;
}
ans=;
dfs();
if (a[]!=) ans++;
printf("%d",ans);
}