BZOJ3252 攻略 贪心、长链剖分

传送门


给树竟直接给父子关系!!!真良心

首先一个贪心策略:每一次选择的链一定是所有链中权值最大的。这应该比较显然

那么我们接下来考虑如何维护这个贪心。我们可以使用长链剖分进行维护,对权值进行长链剖分,然后取前$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 }

 

转载于:https://www.cnblogs.com/Itst/p/10077158.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值