[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[100010],dep[100010],maxn[100100],ans;
struct node{int y,nxt;
}g[100010];int h[100010];
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]+1;
        dfs(g[i].y);
        maxn[x]=max(maxn[x],maxn[g[i].y]);
    }
    maxn[x]=max(maxn[x],dep[x]);
    if (x==1) return;
    if (maxn[x]-dep[x]>=k-1&&a[x]!=1||(maxn[x]-dep[x]>=k)) maxn[x]=0,ans++;
}
int main()
{
    scanf("%d%d",&n,&k);
    scanf("%d",&a[1]);
    for (int i=2;i<=n;i++) 
    {
        scanf("%d",&a[i]);    
        g[i]=node{i,h[a[i]]};h[a[i]]=i;    
    }
    ans=0;
    dfs(1);
    if (a[1]!=1) ans++;
    printf("%d",ans);
}

 

posted @ 2018-08-17 14:26  _雨后阳光  阅读(314)  评论(0编辑  收藏  举报