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

猜你喜欢

转载自www.cnblogs.com/-guz/p/9822541.html
今日推荐