码迷,mamicode.com
首页 > 其他好文 > 详细

【bzoj 3252】攻略

时间:2019-04-09 20:42:02      阅读:128      评论:0      收藏:0      [点我收藏+]

标签:.com   string   pre   +=   就是   online   lin   最大的   const   

题意

我们想到一个贪心,就是每次找到根路径前缀和最大的一个点,取走这条路径,同时把这条路径上的点权变成\(0\)

正确性显然

进一步发现我们需要从树上选择\(m\)条链使得链的总和最大

于是我们考虑换上长链剖分,长儿子定义为往下走点权最大的儿子,每次把最长的路径取走就好了

来一个堆维护一下就好了

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#define re register
#define LL long long
#define mp std::make_pair
typedef std::pair<LL,int> pii;
const int maxn=200006;
inline int read() {
    char c=getchar();int x=0;while(c<'0'||x>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
std::priority_queue<pii> q;
struct E{int v,nxt;}e[maxn];
int head[maxn],a[maxn],son[maxn],vis[maxn];LL len[maxn];
int n,m,num;
inline void add(int x,int y) {
    e[++num].v=y;e[num].nxt=head[x];head[x]=num;
}
void dfs1(int x) {
    for(re int i=head[x];i;i=e[i].nxt) {
        dfs1(e[i].v);
        if(len[e[i].v]>len[son[x]]) son[x]=e[i].v;
    }
    len[x]=len[son[x]]+a[x];
}
int main() {
    n=read(),m=read();
    for(re int i=1;i<=n;i++) a[i]=read();
    for(re int x,y,i=1;i<n;i++) {
        x=read(),y=read(),add(x,y);
    }
    dfs1(1);
    for(re int i=1;i<=n;i++) q.push(mp(len[i],i));
    int tot=0;LL ans=0;
    while(tot<m) {
        int k=q.top().second;q.pop();
        if(vis[k]) continue;
        ans+=len[k];tot++;
        while(k&&!vis[k]) vis[k]=1,k=son[k];
    }
    printf("%lld\n",ans);
    return 0;
}

【bzoj 3252】攻略

标签:.com   string   pre   +=   就是   online   lin   最大的   const   

原文地址:https://www.cnblogs.com/asuldb/p/10679293.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!