bzoj 3252 攻略 长链剖分

题目链接

https://www.lydsy.com/JudgeOnline/problem.php?id=3252

做法

贪心应该还是比较好像的,每一次走最长的链,然后这条链上点的权值就都为0了,那么我们发现题意转化成为一棵数分成若干条链,然后去前k大的链求加和。
那么这个链是怎么划分的呢,根据这个贪心可以发现,长链剖分一下就好了。
因为长链剖分会找到到叶子的最长的链,然后长链剖分中的链都是不相交的,所以就是对的了。

代码

#include<cstdio>
#include<algorithm>
#include<cctype>
#include<cstring>
#include<iostream>
#include<cmath>
#define LL long long
#define N (200005)
using namespace std;
int n,k,x,y,t,tot; 
int son[N],a[N],nxt[N],head[N],data[N];
LL q[N],dep[N],ans;
template <typename T> void read(T&t) {
    t=0;
    bool fl=true;
    char p=getchar();
    while (!isdigit(p)) {
        if (p=='-') fl=false;
        p=getchar();
    }
    do {
        (t*=10)+=p-48;p=getchar();
    }while (isdigit(p));
    if (!fl) t=-t;
}
inline void add(int x,int y){
    a[++tot]=y,nxt[tot]=head[x],head[x]=tot;
}
void dfs(int u){
    for (int p=head[u];p;p=nxt[p]){
        dfs(a[p]);
        if (dep[a[p]]>dep[u]){
            dep[u]=dep[a[p]];
            son[u]=a[p];
        } 
    }
    dep[u]+=data[u];
}
void dfs2(int u,LL dis){
    if (!son[u]){
        q[++t]=-dis;
    }
    else dfs2(son[u],dis+data[son[u]]);
    for (int p=head[u];p;p=nxt[p]){
        if (a[p]!=son[u]) dfs2(a[p],data[a[p]]);
    }
}
int main(){
    read(n),read(k);
    for (int i=1;i<=n;i++) read(data[i]);
    for (int i=1;i<n;i++){
        read(x),read(y);
        add(x,y);
    }
    dfs(1);
    dfs2(1,data[1]);
    nth_element(q+1,q+k+1,q+t+1);
    for (int i=1;i<=k;i++) ans+=q[i];
    printf("%lld",-ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36056315/article/details/80770334