给树竟直接给父子关系!!!真良心
首先一个贪心策略:每一次选择的链一定是所有链中权值最大的。这应该比较显然
那么我们接下来考虑如何维护这个贪心。我们可以使用长链剖分进行维护,对权值进行长链剖分,然后取前$K$大的链权值和,就是答案了。
考虑这个贪心为什么是对的。假设我们选到了第$i$条链,意味着第$i$条链的链顶的所有祖先都一定已经被访问过了(否则它一定是其父亲的儿子中链最长的点,它就不会是链顶),所以选择这一条链的意义就是选择从根到这一条链的链底的路径。
1 #include<bits/stdc++.h> 2 #define int long long 3 //This code is written by Itst 4 using namespace std; 5 6 inline int read(){ 7 int a = 0; 8 bool f = 0; 9 char c = getchar(); 10 while(c != EOF && !isdigit(c)){ 11 if(c == '-') 12 f = 1; 13 c = getchar(); 14 } 15 while(c != EOF && isdigit(c)){ 16 a = (a << 3) + (a << 1) + (c ^ '0'); 17 c = getchar(); 18 } 19 return f ? -a : a; 20 } 21 22 const int MAXN = 200010; 23 struct Edge{ 24 int end , upEd; 25 }Ed[MAXN << 1]; 26 int head[MAXN] , len[MAXN] , maxLen[MAXN] , son[MAXN] , ans[MAXN] , val[MAXN] , N , K , cnt , cntEd; 27 28 inline void addEd(int a , int b){ 29 Ed[++cntEd].end = b; 30 Ed[cntEd].upEd = head[a]; 31 head[a] = cntEd; 32 } 33 34 void dfs1(int x , int p){ 35 maxLen[x] = len[x] = val[x] + len[p]; 36 for(int i = head[x] ; i ; i = Ed[i].upEd){ 37 dfs1(Ed[i].end , x); 38 if(maxLen[Ed[i].end] > maxLen[x]){ 39 maxLen[x] = maxLen[Ed[i].end]; 40 son[x] = Ed[i].end; 41 } 42 } 43 } 44 45 void dfs2(int x , int t){ 46 if(t == x) 47 ans[++cnt] = maxLen[x] - len[x] + val[x]; 48 for(int i = head[x] ; i ; i = Ed[i].upEd) 49 dfs2(Ed[i].end , Ed[i].end == son[x] ? t : Ed[i].end); 50 } 51 52 bool cmp(int a , int b){ 53 return a > b; 54 } 55 56 signed main(){ 57 #ifndef ONLINE_JUDGE 58 freopen("3252.in" , "r" , stdin); 59 //freopen("3252.out" , "w" , stdout); 60 #endif 61 N = read(); 62 K = read(); 63 for(int i = 1 ; i <= N ; ++i) 64 val[i] = read(); 65 for(int i = 1 ; i < N ; ++i){ 66 int a = read() , b = read(); 67 addEd(a , b); 68 } 69 dfs1(1 , 0); 70 dfs2(1 , 1); 71 sort(ans + 1 , ans + cnt + 1 , cmp); 72 int sum = 0; 73 for(int i = 1 ; i <= K ; ++i) 74 sum += ans[i]; 75 cout << sum; 76 return 0; 77 }