这个题目应该算是今年省选最简单的一题了 然而为什么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;
}