不知道扯啥了,就想构造个密码,然而搜狗打不出来“横折弯”,百度上也没搜出来。。。
所以这不就有的扯了吗
考虑一个贪心:每次取权值最大的路径,然后把这条路径上的点权清空。
不会理性证明,那就感性理解一下,看起来挺对的。
用不大一样的长剖优化。不以深度划分长短儿子,而是以权值和划分,然后把所有长链扔到堆里取前$k$大。
正确性的话,根据上面的贪心,某个点一定是被它下面最大的一条路径取走。这若干条不相交的链就可以代表取走每个叶子时的权值。
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <queue>
#define maxn 200005
#define inf 0x3f3f3f3f
using namespace std;
inline int read(){
int x=0,y=0;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')y=1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return y?-x:x;
}
priority_queue<long long>q;
long long md[maxn];
int son[maxn],a[maxn],top[maxn],h[maxn],num;
struct edge{int pre,to;}e[maxn];
inline void add(int from,int to){e[++num]=(edge){h[from],to},h[from]=num;}
void dfs1(int node=1){
md[node]=a[node];
for(register int i=h[node],x;i;i=e[i].pre){
x=e[i].to,dfs1(x);
if(md[x]>md[son[node]])son[node]=x,md[node]=md[x]+a[node];
}
}
void dfs2(int node=1){
if(top[node]==node)q.push(md[node]);
if(!son[node])return;
top[son[node]]=top[node],dfs2(son[node]);
for(register int i=h[node],x;i;i=e[i].pre){
x=e[i].to;
if(x!=son[node])top[x]=x,dfs2(x);
}
}
int main(){
top[1]=1;
int n=read(),k=read();
long long ans=0;
for(register int i=1;i<=n;++i)a[i]=read();
for(register int i=1,x;i<n;++i)x=read(),add(x,read());
dfs1(),dfs2();
while(k--)ans+=q.top(),q.pop();
printf("%lld\n",ans);
}