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

bzoj3252: 攻略

时间:2018-11-13 14:19:43      阅读:98      评论:0      收藏:0      [点我收藏+]

标签:def   tps   define   mes   lld   mina   \n   bzoj   code   

传送门

给定一棵树,每个点有点权,选定\(k\)个叶子,满足根到\(k\)个叶子的所有路径所覆盖的点权和最大。

首先考虑一个贪心,每一次选择权值最大的一条链,然后把这条链上的权值清零,重复\(k\)

于是很显然这样的贪心可以等价于把这棵树给剖成若干条链。那么考虑用长链剖分来搞,只要把链的长度换成所有点的权值和就可以了。把所有的链的权值sort一下取前\(k\)大就行了

//minamoto
#include<bits/stdc++.h>
#define ll long long
using namespace std;
#define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1<<21],*p1=buf,*p2=buf;
int read(){
    int res,f=1;char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
const int N=5e5+5;
int head[N],Next[N<<1],ver[N<<1],tot;
inline void add(int u,int v){ver[++tot]=v,Next[tot]=head[u],head[u]=tot;}
int a[N],n,k,son[N],top;ll mx[N],st[N],ans;
void dfs1(int u){
    for(int i=head[u];i;i=Next[i]){
        int v=ver[i];dfs1(v);
        if(mx[v]>mx[son[u]])son[u]=v;
    }
    mx[u]=mx[son[u]]+a[u];
}
void dfs2(int u,int tp){
    if(u==tp)st[++top]=mx[u];
    if(son[u])dfs2(son[u],tp);
    for(int i=head[u];i;i=Next[i])
    if(ver[i]!=son[u])dfs2(ver[i],ver[i]);
}
int main(){
//  freopen("testdata.in","r",stdin);
    n=read(),k=read();
    for(int i=1;i<=n;++i)a[i]=read();
    for(int i=1,u,v;i<n;++i)u=read(),v=read(),add(u,v);
    dfs1(1),dfs2(1,1),sort(st+1,st+1+top);
    for(int i=top,j=k;i&&j;--i,--j)ans+=st[i];
    printf("%lld\n",ans);return 0;
}

bzoj3252: 攻略

标签:def   tps   define   mes   lld   mina   \n   bzoj   code   

原文地址:https://www.cnblogs.com/bztMinamoto/p/9951603.html

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