P5290 [十二省联考 2019] 春节十二响

题意

给一棵 \(n\) 个节点的树,定义一个点集的权值为这个点集中点权最大值。要求把整棵树分成若干个点集,满足同一个点集内不存在祖先关系,并且所有点集的权值和最小。
\(n\le2\times10^5\)

思路

对于每个点开一个堆存以祂为根的子树中,最优划分情况下需要支付那些代价。在每个点处,贪心地把子树 \(merge\) 起来。具体的,把最大和最大分一组,次大和次大分一组……全部 \(merge\) 完后把当前节点的权值也塞进去。过程中可以用启发式合并。

代码

// Problem: P5290 [十二省联考 2019] 春节十二响
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P5290
// Memory Limit: 500 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
namespace IO{
    template<typename T>
    inline void read(T&x){
        x=0;char c=getchar();bool f=0;
        while(!isdigit(c)) c=='-'?f=1:0,c=getchar();
        while(isdigit(c)) x=x*10+c-'0',c=getchar();
        f?x=-x:0;
    }
    template<typename T>
    inline void write(T x){
        if(x==0){putchar('0');return ;}
        x<0?x=-x,putchar('-'):0;short st[50],top=0;
        while(x) st[++top]=x%10,x/=10;
        while(top) putchar(st[top--]+'0');
    }
    inline void read(char&c){c=getchar();while(isspace(c)) c=getchar();}
    inline void write(char c){putchar(c);}
    inline void read(string&s){s.clear();char c;read(c);while(!isspace(c)&&~c) s+=c,c=getchar();}
    inline void write(string s){for(int i=0,len=s.size();i<len;i++) putchar(s[i]);}
    template<typename T>inline void write(T*x){while(*x) putchar(*(x++));}
    template<typename T,typename...T2> inline void read(T&x,T2&...y){read(x),read(y...);}
    template<typename T,typename...T2> inline void write(const T x,const T2...y){write(x),putchar(' '),write(y...),sizeof...(y)==1?putchar('\n'):0;}
}using namespace IO;
#define LL long long
const int maxn=200010;
int n,val[maxn],fa[maxn],d[maxn];
vector<int>e[maxn];
priority_queue<int>q[maxn],ls;
queue<int>qu;
signed main(){
    read(n);
    for(int i=1;i<=n;i++) read(val[i]);
    for(int i=2;i<=n;i++) read(fa[i]),e[fa[i]].push_back(i);
    for(int i=1;i<=n;i++) if(e[i].size()==0) qu.push(i);
    while(!qu.empty()){
        int u=qu.front();
        qu.pop();
        d[fa[u]]++;
        if(d[fa[u]]==e[fa[u]].size()) qu.push(fa[u]);
        for(int v:e[u]){
            if(q[u].size()<q[v].size()) swap(q[u],q[v]);
            while(!q[v].empty()){
                ls.push(max(q[u].top(),q[v].top()));
                q[u].pop(),q[v].pop();
            }
            while(!ls.empty()) q[u].push(ls.top()),ls.pop();
        }
        q[u].push(val[u]);
    }
    LL ans=0;
    while(!q[1].empty()) ans+=q[1].top(),q[1].pop();
    write(ans);
    return 0;
}
posted @ 2026-06-15 15:56  Link-Cut_Trees  阅读(8)  评论(0)    收藏  举报