[bzoj3252]攻略

14 篇文章 0 订阅

题目描述

众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏。
今天他得到了一款新游戏《XX半岛》,这款游戏有n个场景(scene),某些场景可以通过不同的选择支到达其他场景。所有场景和选择支构成树状结构:开始游戏时在根节点(共通线),叶子节点为结局。每个场景有一个价值,现在桂马开启攻略之神模式,同时攻略k次该游戏,问他观赏到的场景的价值和最大是多少(同一场景观看多次是不能重复得到价值的)
“为什么你还没玩就知道每个场景的价值呢?”
“我已经看到结局了。”

贪心

对每个点处理从它往下取的最大值以及最优情况下往哪个儿子里去。
然后全部扔进数据结构里。
取k次,每次取出最大的,然后在数据结构中删除其往下路径上的点。
易证。

#include<cstdio>
#include<algorithm>
#include<set>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int maxn=200000+10;
struct dong{
    int x;
    ll data;
    friend bool operator <(dong a,dong b){
        return a.data>b.data||a.data==b.data&&a.x>b.x;
    }
};
multiset<dong> s;
int h[maxn],go[maxn*2],next[maxn*2],g[maxn];
ll f[maxn],a[maxn];
int i,j,k,l,t,n,m,tot;
ll ans;
dong zlt;
ll read(){
    ll x=0;
    char ch=getchar();
    while (ch<'0'||ch>'9') ch=getchar();
    while (ch>='0'&&ch<='9'){
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x;
}
void add(int x,int y){
    go[++tot]=y;
    next[tot]=h[x];
    h[x]=tot;
}
void dfs(int x,int y){
    int t=h[x],j=0;
    while (t){
        if (go[t]!=y){
            dfs(go[t],x);
            if (!j||f[go[t]]>f[j]) j=go[t];
        }
        t=next[t];
    }
    g[x]=j;
    f[x]=f[j]+a[x];
}
int main(){
    //freopen("galgame5.in","r",stdin);
    n=read();m=read();
    fo(i,1,n) a[i]=read();
    fo(i,1,n-1){
        j=read();k=read();
        add(j,k);add(k,j);
    }
    dfs(1,0);
    fo(i,1,n){
        zlt.x=i;
        zlt.data=f[i];
        s.insert(zlt);
    }
    while (m--){
        if (s.empty()) break;
        zlt=*s.begin();
        ans+=zlt.data;
        j=zlt.x;
        while (j){
            zlt.x=j;
            zlt.data=f[j];
            s.erase(zlt);
            j=g[j];
        }
    }
    printf("%lld\n",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值