1. 程式人生 > >Dfs【bzoj3252】攻略

Dfs【bzoj3252】攻略

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