给树竟直接给父子关系!!!真良心
首先一个贪心策略:每一次选择的链一定是所有链中权值最大的。这应该比较显然
那么我们接下来考虑如何维护这个贪心。我们可以使用长链剖分进行维护,对权值进行长链剖分,然后取前$K$大的链权值和,就是答案了。
考虑这个贪心为什么是对的。假设我们选到了第$i$条链,意味着第$i$条链的链顶的所有祖先都一定已经被访问过了(否则它一定是其父亲的儿子中链最长的点,它就不会是链顶),所以选择这一条链的意义就是选择从根到这一条链的链底的路径。
#include<bits/stdc++.h> #define int long long //This code is written by Itst using namespace std; inline int read(){ ; ; char c = getchar(); while(c != EOF && !isdigit(c)){ if(c == '-') f = ; c = getchar(); } while(c != EOF && isdigit(c)){ a = (a << ) + (a << ) + (c ^ '); c = getchar(); } return f ? -a : a; } ; struct Edge{ int end , upEd; }Ed[MAXN << ]; int head[MAXN] , len[MAXN] , maxLen[MAXN] , son[MAXN] , ans[MAXN] , val[MAXN] , N , K , cnt , cntEd; inline void addEd(int a , int b){ Ed[++cntEd].end = b; Ed[cntEd].upEd = head[a]; head[a] = cntEd; } void dfs1(int x , int p){ maxLen[x] = len[x] = val[x] + len[p]; for(int i = head[x] ; i ; i = Ed[i].upEd){ dfs1(Ed[i].end , x); if(maxLen[Ed[i].end] > maxLen[x]){ maxLen[x] = maxLen[Ed[i].end]; son[x] = Ed[i].end; } } } void dfs2(int x , int t){ if(t == x) ans[++cnt] = maxLen[x] - len[x] + val[x]; for(int i = head[x] ; i ; i = Ed[i].upEd) dfs2(Ed[i].end , Ed[i].end == son[x] ? t : Ed[i].end); } bool cmp(int a , int b){ return a > b; } signed main(){ #ifndef ONLINE_JUDGE freopen("3252.in" , "r" , stdin); //freopen("3252.out" , "w" , stdout); #endif N = read(); K = read(); ; i <= N ; ++i) val[i] = read(); ; i < N ; ++i){ int a = read() , b = read(); addEd(a , b); } dfs1( , ); dfs2( , ); sort(ans + , ans + cnt + , cmp); ; ; i <= K ; ++i) sum += ans[i]; cout << sum; ; }