题目链接
https://www.lydsy.com/JudgeOnline/problem.php?id=3252
做法
贪心应该还是比较好像的,每一次走最长的链,然后这条链上点的权值就都为0了,那么我们发现题意转化成为一棵数分成若干条链,然后去前k大的链求加和。
那么这个链是怎么划分的呢,根据这个贪心可以发现,长链剖分一下就好了。
因为长链剖分会找到到叶子的最长的链,然后长链剖分中的链都是不相交的,所以就是对的了。
代码
#include<cstdio>
#include<algorithm>
#include<cctype>
#include<cstring>
#include<iostream>
#include<cmath>
#define LL long long
#define N (200005)
using namespace std;
int n,k,x,y,t,tot;
int son[N],a[N],nxt[N],head[N],data[N];
LL q[N],dep[N],ans;
template <typename T> void read(T&t) {
t=0;
bool fl=true;
char p=getchar();
while (!isdigit(p)) {
if (p=='-') fl=false;
p=getchar();
}
do {
(t*=10)+=p-48;p=getchar();
}while (isdigit(p));
if (!fl) t=-t;
}
inline void add(int x,int y){
a[++tot]=y,nxt[tot]=head[x],head[x]=tot;
}
void dfs(int u){
for (int p=head[u];p;p=nxt[p]){
dfs(a[p]);
if (dep[a[p]]>dep[u]){
dep[u]=dep[a[p]];
son[u]=a[p];
}
}
dep[u]+=data[u];
}
void dfs2(int u,LL dis){
if (!son[u]){
q[++t]=-dis;
}
else dfs2(son[u],dis+data[son[u]]);
for (int p=head[u];p;p=nxt[p]){
if (a[p]!=son[u]) dfs2(a[p],data[a[p]]);
}
}
int main(){
read(n),read(k);
for (int i=1;i<=n;i++) read(data[i]);
for (int i=1;i<n;i++){
read(x),read(y);
add(x,y);
}
dfs(1);
dfs2(1,data[1]);
nth_element(q+1,q+k+1,q+t+1);
for (int i=1;i<=k;i++) ans+=q[i];
printf("%lld",-ans);
return 0;
}