[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); }