【BZOJ3252】攻略(长链剖分,贪心)

【BZOJ3252】攻略(长链剖分,贪心)

题面

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

题解

一个假装是对的贪心:
每次选择最大的路径,然后将路径上所有点的权值清零。
那么我们可以用长链剖分来实现这个贪心。
链长改为最大的路径权值和,这样子把每条重链的权值丢进一个堆里面取\(k\)次即可。
正确性自己\(YY\)一下,发现是对的

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
#define ll long long
#define MAX 200200
inline int read()
{
	int x=0;bool t=false;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=true,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return t?-x:x;
}
priority_queue<ll> Q;
struct Line{int v,next;}e[MAX<<1];
int h[MAX],cnt=1;
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
int a[MAX],n,K,hson[MAX];
ll ms[MAX],ans;
void dfs1(int u)
{
	for(int i=h[u];i;i=e[i].next)
	{
		int v=e[i].v;dfs1(v);
		if(ms[v]>ms[hson[u]])hson[u]=v;
	}
	ms[u]+=a[u]+ms[hson[u]];
}
void dfs2(int u,int tp)
{
	if(u==tp)Q.push(ms[u]);
	if(hson[u])dfs2(hson[u],tp);
	for(int i=h[u];i;i=e[i].next)
		if(e[i].v!=hson[u])dfs2(e[i].v,e[i].v);
}
int main()
{
	n=read();K=read();
	for(int i=1;i<=n;++i)a[i]=read();
	for(int i=1,x,y;i<n;++i)x=read(),y=read(),Add(x,y);
	dfs1(1);dfs2(1,1);
	while(K&&!Q.empty())ans+=Q.top(),Q.pop(),--K;
	printf("%lld\n",ans);
	return 0;
}

posted @ 2018-08-13 22:16  小蒟蒻yyb  阅读(...)  评论(...编辑  收藏