bzoj 3252攻略

Posted asuldb

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 3252攻略相关的知识,希望对你有一定的参考价值。

题意

我们想到一个贪心,就是每次找到根路径前缀和最大的一个点,取走这条路径,同时把这条路径上的点权变成(0)

正确性显然

进一步发现我们需要从树上选择(m)条链使得链的总和最大

于是我们考虑换上长链剖分,长儿子定义为往下走点权最大的儿子,每次把最长的路径取走就好了

来一个堆维护一下就好了

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#define re register
#define LL long long
#define mp std::make_pair
typedef std::pair<LL,int> pii;
const int maxn=200006;
inline int read() {
    char c=getchar();int x=0;while(c<'0'||x>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
std::priority_queue<pii> q;
struct E{int v,nxt;}e[maxn];
int head[maxn],a[maxn],son[maxn],vis[maxn];LL len[maxn];
int n,m,num;
inline void add(int x,int y) {
    e[++num].v=y;e[num].nxt=head[x];head[x]=num;
}
void dfs1(int x) {
    for(re int i=head[x];i;i=e[i].nxt) {
        dfs1(e[i].v);
        if(len[e[i].v]>len[son[x]]) son[x]=e[i].v;
    }
    len[x]=len[son[x]]+a[x];
}
int main() {
    n=read(),m=read();
    for(re int i=1;i<=n;i++) a[i]=read();
    for(re int x,y,i=1;i<n;i++) {
        x=read(),y=read(),add(x,y);
    }
    dfs1(1);
    for(re int i=1;i<=n;i++) q.push(mp(len[i],i));
    int tot=0;LL ans=0;
    while(tot<m) {
        int k=q.top().second;q.pop();
        if(vis[k]) continue;
        ans+=len[k];tot++;
        while(k&&!vis[k]) vis[k]=1,k=son[k];
    }
    printf("%lld
",ans);
    return 0;
}

以上是关于bzoj 3252攻略的主要内容,如果未能解决你的问题,请参考以下文章

线段树 BZOJ3252 攻略

BZOJ-3252攻略 DFS序 + 线段树 + 贪心

bzoj3252

bzoj3252: 攻略

BZOJ_3252_攻略_线段树+dfs序

BZOJ3252: 攻略