這道題其實很簡單,求k個到根的鏈,使得鏈上的節點的個數儘量多,若是節點被計算過了,就不能再被計算了,其實咱們發現,只要k>=葉子節點,那麼確定是所有,因此咱們考慮全部的葉子節點,DFS到根節點後,往上遞歸,咱們能比較容易的求出某個節點,全部兒子節點的最深深度,那麼對於上面一個節點,其實只有一個最長那個影響,全部咱們能夠保存每一個節點的最深深度,而後往上遞歸,遞歸到某個節點的時候,查詢全部子樹的最深深度,把這個最深深度+1當場當前節點的最深深度,其餘節點實際上已經變成鏈了,那麼咱們用優先隊列保存全部的鏈,也就是對應鏈的長度,而後找出前k大的鏈,求和便可,這樣就不會重複了。c++
#include<bits/stdc++.h> using namespace std; const int maxx = 2e5+6; int ver[maxx],edge[maxx],head[maxx],Next[maxx]; int n,k,tot; priority_queue<int>q; int d[maxx]; void add(int x,int y){ ver[++tot]=y;Next[tot]=head[x];head[x]=tot; ver[++tot]=x;Next[tot]=head[y];head[y]=tot; } int dfs(int u,int fa){ d[u]=1; priority_queue<int>s; s.push(d[u]); for (int i=head[u];i;i=Next[i]){ int v=ver[i]; if (v==fa)continue; dfs(v,u); s.push(d[v]+1); } d[u]=s.top(); s.pop(); while(s.size()){ q.push(s.top()-1); s.pop(); } } int main(){ while(~scanf("%d%d",&n,&k)){ for (int i=2;i<=n;i++){ int tmp; scanf("%d",&tmp); add(i,tmp); } dfs(1,0); q.push(d[1]); int sz=q.size(); int ans=0; for (int i=1;i<=min(sz,k);i++){ ans+=q.top(); q.pop(); } printf("%d\n",ans); } return 0; }