题解:2019十二省联考 春节十二响

这个题目应该算是今年省选最简单的一题了 然而为什么HB就是有wjyyy切了呢

首先来说一下贪心的思想(考场上应该想出来的人很多)
由于在同一条链上不能同时选,但是在不同的练上是相互不影响,我们用两个队列来表示
比如举个例子(就是一条链的情况吧)
我们把1的两个儿子底下的一整条链先求出来,然后排个序(由于考虑到同一条链不能同时选,所以内部的顺序并不影响)
假如排完了是这样的情况:

\[a:10,8,6,4,2,1 \]

\[b: 9,7,7,5 \]

我们来看怎么贪心,如果把10和9放在一起,那么只会产生10的影响,否则一共会产生10+9的影响,也就是说,只有和10一起才能消掉9,于是我们的操作就是把10加进答案,然后弹出9,10,同样,8加进答案,弹出7,8,就这样,最后剩下的数1,2单独加入
于是这样就是一个贪心,于是链的15分(复杂度\(NlogN\))

同样,结合这个贪心,我们可以拓展到整棵树上,用优先队列进行维护,复杂度\(N^2logN\),得分60

然而,如果使用启发式合并,由于每次操作只会弹两个,进一次,所以复杂度就是\(NlogN\),于是就可以有好的切掉了

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
using namespace std;

#define re register
#define ll long long
#define gc getchar()
inline int read()
{
 	re int x(0),f(1);re char c(gc);
    while(c>'9'||c<'0')f=c=='-'?-1:1,c=gc;
    while(c>='0'&&c<='9')x=x*10+c-48,c=gc;
    return f*x;
}

const int N=1100000;
struct node{int to,next;}e[N];
int h[N],cnt,tot,n,po[N];
ll ans,val[N],now[N];
priority_queue<ll> son[N];
void add(int x,int y){e[++cnt]=(node){y,h[x]};h[x]=cnt;} 
#define QXX(u) for(int i=h[u],v;v=e[i].to,i;i=e[i].next)

void dfs(int u)
{
    po[u]=u;
 	QXX(u)
    {
        dfs(v);
     	if(i==h[u])	po[u]=po[v];
        else
        {
         	if(son[po[u]].size()<son[po[v]].size())
                swap(po[u],po[v]);
            tot=0;
            while(!son[po[v]].empty())
            {
                now[++tot]=max(son[po[v]].top(),son[po[u]].top());
                son[po[u]].pop();
                son[po[v]].pop();
            }
            for(int j=1;j<=tot;j++)
                son[po[u]].push(now[j]);
        } 
    }
    son[po[u]].push(val[u]);
} 
int main()
{
    n=read();
    for(re int i=1;i<=n;i++)
        val[i]=read();
    for(re int i=2;i<=n;i++)
    {
     	int fa=read();
         add(fa,i);
    } 
    dfs(1);
    while(!son[po[1]].empty())
        ans+=son[po[1]].top(),son[po[1]].pop();
    cout<<ans;
    return 0;
} 
原文地址:https://www.cnblogs.com/zijinjun/p/10694784.html