看了20分钟硬是没看懂他在说什么
膜了题解之后
实际上就是一棵树,求一个代价最大的拓扑序
发现对于一个点选了之后会有一些更小的儿子必须选
即对于2个点
满足
用一个堆维护每一次找最小的一个就行了
#include<bits/stdc++.h>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;
using namespace __gnu_pbds;
#define re register
#define ll long long
#define db long double
#define pii pair<db,int>
typedef __gnu_pbds::priority_queue <pii,greater<pii>,pairing_heap_tag> Heap;
typedef Heap::point_iterator it;
const int RLEN=1<<20|1;
inline char nc() {
static char ibuf[RLEN],*ib,*ob;
(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob) ? -1 : *ib++;
}
inline int read() {
char ch=nc(); int i=0,f=1;
while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
return i*f;
}
const int N=500005;
int n,a[N],fa[N],f[N],w[N],dfn;
bool vis[N],o[N];
ll ans,sum[N],siz[N];
int adj[N],nxt[N<<1],to[N<<1],cnt,tot;
it pos[N];Heap q;
inline void addedge(int u,int v){
nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v;
}
int find(int x){
return fa[x]==x?x:fa[x]=find(fa[x]);
}
bool dfs(int u){
++dfn,vis[u]=true,fa[u]=u;
for(int e=adj[u];e;e=nxt[e]){
int v=to[e];
if(vis[v])return false;
f[v]=u;if(!dfs(v))return false;
}
return true;
}
int main(){
n=read();
for(re int i=1;i<=n;++i)a[i]=read(),addedge(a[i],i);
for(re int i=1;i<=n;++i)w[i]=read(),sum[i]=w[i],siz[i]=1;siz[0]=1;
if(!dfs(0)||dfn!=n+1){puts("-1");return 0;}
for(re int i=0;i<=n;++i)pos[i]=q.push(pii((db)sum[i]/siz[i],i));
while(!q.empty()){
int u=q.top().second;q.pop();
if(!u||o[find(f[u])]){
ans+=tot*sum[u];
tot+=siz[u];
o[u]=1;
}
else{
int f1=find(f[u]);
ans+=siz[f1]*sum[u];
siz[f1]+=siz[u];
sum[f1]+=sum[u];
fa[u]=f1;
q.modify(pos[f1],pii((db)sum[f1]/siz[f1],f1));
}
}
cout<<ans;
}