十二省联考2019 春节十二响

时间:2022-11-17 21:28:02

十二省联考2019 春节十二响


本质上也是傻逼题,全场切的那种。

但是一开始想不到,然后怎么想到呢?

“注意:在第 10、11、12 号测试点中,1 号子程序不一定是链的一个端点。”

我就看了一眼树是一条链的部分分

哇傻逼玩意儿啊,不是两边sort一下答案就是\(\sum \max\)

然后想想不是一条链怎么做

首先可以想到树形dp,那么一个子树树根肯定只能单独拿出来,所以不管了

然后根据套路想怎么合并两个儿子

???好像就是两个儿子sort以后前面一段\(\max\)

然后拿个堆维护这玩意儿,启发式合并一下就完事了

#include<bits/stdc++.h>
#define il inline
#define vd void
typedef long long ll;
il ll gi(){
    ll x=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')f=-1;
        ch=getchar();
    }
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int M[200010],fir[200010],dis[400010],nxt[400010],id;
il vd link(int a,int b){nxt[++id]=fir[a],fir[a]=id,dis[id]=b;}
std::priority_queue<int>que[200010];
il vd dfs(int x,int fa=-1){
    for(int i=fir[x];i;i=nxt[i]){
        if(fa==dis[i])continue;
        dfs(dis[i],x);
        if(que[x].size()<que[dis[i]].size())que[x].swap(que[dis[i]]);
        std::vector<int>merged;
        while(!que[dis[i]].empty())merged.push_back(std::max(que[x].top(),que[dis[i]].top())),que[x].pop(),que[dis[i]].pop();
        for(auto j:merged)que[x].push(j);
    }
    que[x].push(M[x]);
}
int main(){
#ifdef XZZSB
    freopen("in.in","r",stdin);
    freopen("out.out","w",stdout);
#endif
    int n=gi();
    for(int i=1;i<=n;++i)M[i]=gi();
    for(int i=2;i<=n;++i)link(gi(),i);
    dfs(1);
    ll ans=0;
    while(!que[1].empty())ans+=que[1].top(),que[1].pop();
    printf("%lld\n",ans);
    return 0;
}