题目链接
LOJ:https://loj.ac/problem/3052
洛谷:https://www.luogu.org/problemnew/show/P5290
BZOJ:https://www.lydsy.com/JudgeOnline/problem.php?id=5499
Solution
部分分有一个链的情况极大的提示了正解。
考虑链情况怎么做,显然是\(1\)号节点向下延伸出了两条支链,那么我们可以分别\(\rm sort\)然后最大的和最大的成对,次打的同理,这样显然是最优的。
那么我们考虑二叉树怎么做,同样对于点\(x\)我们开一个堆记录这个点的子树的使用信息,那么点\(x\)可以通过两个儿子按照链情况一样的合并得到。
普通的树同理,如果我们加一个启发式合并就可以做到\(O(n\log n)\)。
注意启发式合并的时候有一个\(\rm swap\)堆的过程,这玩意在\(\rm BZOJ\)好像会发生奇怪的错误反正窝是MLE了,所以我们记个编号就好了。好像原因是因为BZOJ不支持c++11...
#include<bits/stdc++.h>
using namespace std;
void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
#define ll long long
void print(ll x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(ll x) {if(!x) putchar('0');else print(x);putchar('\n');}
#define lf double
#define pii pair<int,int >
#define vec vector<int >
#define pb push_back
#define mp make_pair
#define fr first
#define sc second
const int maxn = 2e5+10;
const int inf = 1e9;
const lf eps = 1e-8;
int head[maxn],tot,n,a[maxn],sta[maxn],top,id[maxn];
struct edge{int to,nxt;}e[maxn<<1];
priority_queue<int > s[maxn];
void add(int u,int v) {e[++tot]=(edge){v,head[u]},head[u]=tot;}
void ins(int u,int v) {add(u,v),add(v,u);}
void dfs(int x,int fa) {
for(int v,i=head[x];i;i=e[i].nxt) {
if((v=e[i].to)==fa) continue;top=0;dfs(v,x);
if(s[id[v]].size()>s[id[x]].size()) swap(id[x],id[v]);
while(s[id[v]].size()) sta[++top]=max(s[id[x]].top(),s[id[v]].top()),s[id[x]].pop(),s[id[v]].pop();
while(top) s[id[x]].push(sta[top--]);
}s[id[x]].push(a[x]);
}
int main() {
read(n);for(int i=1;i<=n;i++) read(a[i]),id[i]=i;
for(int i=2,x;i<=n;i++) read(x),ins(i,x);
dfs(1,0);ll ans=0;while(s[id[1]].size()) ans+=(ll)s[id[1]].top(),s[id[1]].pop();
write(ans);
return 0;
}