Dfs【bzoj3252】攻略
阿新 • • 發佈:2018-11-08
Description
題目簡述:樹版[k取方格數]
眾所周知,桂木桂馬是攻略之神,開啟攻略之神模式後,他可以同時攻略k部遊戲。
今天他得到了一款新遊戲《XX半島》,這款遊戲有n個場景(scene),某些場景可以通過不同的選擇支到達其他場景。所有場景和選擇支構成樹狀結構:開始遊戲時在根節點(共通線),葉子節點為結局。每個場景有一個價值,現在桂馬開啟攻略之神模式,同時攻略k次該遊戲,問他觀賞到的場景的價值和最大是多少(同一場景觀看多次是不能重複得到價值的)
“為什麼你還沒玩就知道每個場景的價值呢?”
“我已經看到結局了。”
Input
第一行兩個正整數n,k
第二行n個正整數,表示每個場景的價值
以下n-1行,每行2個整數a,b,表示a場景有個選擇支通向b場景(即a是b的父親)
保證場景1為根節點
n<=200000,1<=場景價值<=2^31-1
Output
輸出一個整數表示答案
如果我們的圖是這樣
顯然,這樣我們會選擇\(8\),而不會選擇\(6,5\)。
此時我們按照價值劃分為長短鏈,當前的父親節點\(u\)就帶有價值\(8\),這個時候直接塞過去就好.
此時就可以等價為我們拆成了這樣
此時,我們的答案就轉化為求這些鏈的權值的前\(k\)大的和.
程式碼
#include<cstdio> #include<cctype> #include<algorithm> #define int long long #define R register using namespace std; inline void in(int &x) { int f=1;x=0;char s=getchar(); while(!isdigit(s)){if(s=='-')f=-1;s=getchar();} while(isdigit(s)){x=x*10+s-'0';s=getchar();} x*=f; } int n,k,val[200008],stk[200008],cnt,top,ans; int head[200008],tot,son[200008]; struct cod{int u,v;}edge[500008]; inline void add(int x,int y) { edge[++tot].u=head[x]; edge[tot].v=y; head[x]=tot; } void dfs(int u,int fa) { for(R int i=head[u];i;i=edge[i].u) { if(edge[i].v==fa)continue; dfs(edge[i].v,u); if(val[edge[i].v]>val[son[u]]) son[u]=edge[i].v; } val[u]+=val[son[u]]; for(R int i=head[u];i;i=edge[i].u) { if(edge[i].v==fa or edge[i].v==son[u])continue; if(val[edge[i].v]>val[u]) swap(val[edge[i].v],val[u]); stk[++top]=val[edge[i].v]; } } signed main() { in(n),in(k); for(R int i=1;i<=n;i++)in(val[i]); for(R int i=1,x,y;i<n;i++) { in(x),in(y); add(x,y);add(y,x); } dfs(1,0); stk[++top]=val[1]; sort(stk+1,stk+top+1); for(R int i=top;i>=0;i--) { cnt++; ans+=stk[i]; if(cnt==k)break; } printf("%lld",ans); }