D - Denouncing Mafia DFS

  這道題其實很簡單,求k個到根的鏈,使得鏈上的節點的個數儘可能多,如果節點被計算過了,就不能再被計算了,其實我們發現,只要k>=葉子節點,那麼肯定是全部,所以我們考慮所有的葉子節點,DFS到根節點後,往上遞歸,我們能比較容易的求出某個節點,所有兒子節點的最深深度,那麼對於上面一個節點,其實只有一個最長那個影響,所有我們可以保存每個節點的最深深度,然後往上遞歸,遞歸到某個節點的時候,查詢所有子樹的最深深度,把這個最深深度+1當場當前節點的最深深度,其他節點實際上已經變成鏈了,那麼我們用優先隊列保存所有的鏈,也就是對應鏈的長度,然後找出前k大的鏈,求和即可,這樣就不會重複了。

  

#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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章