【BZOJ5499】[2019省隊聯測]春節十二響(貪心)

【BZOJ5499】[2019省隊聯測]春節十二響(貪心)

題面

BZOJ
洛谷php

題解

若是是一條折鏈,顯然維護兩側的值,每次兩個堆分別彈出一個\(max\)而後合併一下,最後再放回去就能夠了。
那麼如今回到一棵樹上,能夠認爲就是自己有一條鏈,如今每次要合併一條鏈進來,那麼拿一個堆維護這個合併過程就能夠了。爲了保證複雜度用啓發式合併。
\(C++11\)下能夠直接使用\(.swap()\)函數來進行優先隊列的交換。
爲了在\(BZOJ\)上過就寫的普通的啓發式合併。ios

#include<cstdio>
#include<vector>
#include<queue>
using namespace std;
#define MAX 200200
inline int read()
{
    int x=0;bool t=false;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
int n,M[MAX];long long ans;
priority_queue<int> S[MAX];
struct Line{int v,next;}e[MAX];
int h[MAX],cnt=1;
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
int ID[MAX];
void dfs(int u)
{
    ID[u]=u;
    for(int i=h[u];i;i=e[i].next)
    {
        int v=e[i].v;dfs(v);
        if(S[ID[v]].size()>S[ID[u]].size())swap(ID[u],ID[v]);
        vector<int> tmp;
        while(!S[ID[v]].empty())tmp.push_back(max(S[ID[u]].top(),S[ID[v]].top())),S[ID[u]].pop(),S[ID[v]].pop();
        while(!tmp.empty())S[ID[u]].push(tmp.back()),tmp.pop_back();
    }
    S[ID[u]].push(M[u]);
}
/*
void dfs(int u)
{
    for(int i=h[u];i;i=e[i].next)
    {
        int v=e[i].v;dfs(v);
        if(S[v].size()>S[u].size())S[u].swap(S[v]);
        vector<int> tmp;
        while(!S[v].empty())tmp.push_back(max(S[u].top(),S[v].top())),S[u].pop(),S[v].pop();
        while(!tmp.empty())S[u].push(tmp.back()),tmp.pop_back();
    }
    S[u].push(M[u]);
}
*/
int main()
{
    n=read();
    for(int i=1;i<=n;++i)M[i]=read();
    for(int i=2;i<=n;++i)Add(read(),i);
    dfs(1);
    while(!S[ID[1]].empty())ans+=S[ID[1]].top(),S[ID[1]].pop();
    printf("%lld\n",ans);
    return 0;
}
相關文章
相關標籤/搜索