首先把限制翻译一下就是考虑p这个排列,
ai
a
i
必须出现在i前面,连边
ai
a
i
->i。发现约束关系是一棵以0为根的树。(有环就无解)
现在的问题就变为,给定一棵树,每个点有点权,你要给每个点再分配一个不同的
pi
p
i
,需要满足
pi>pfa[i]
p
i
>
p
f
a
[
i
]
,使得
∑ipiai
∑
i
p
i
a
i
最大。
有一种神奇的贪心做法。
先来考虑一个简单的情况:若w[i]< w[fa[i]]且是w最小的儿子。那么选了fa[i]之后下一个一定会选i。那么我们可以把i与fa[i]合并。
这个结论对于一个连通块也是对的,所以块与块之间也可以比较大小,即比较sumw/sz。所以我们可以每次找出权值最小的联通快,将其与他的父亲合并。(考虑两个连通块,如果i在j前面,那么一定满足
wi+wj∗si>wj+wi∗sj
w
i
+
w
j
∗
s
i
>
w
j
+
w
i
∗
s
j
)
可以用并查集+set实现。
复杂度
O(nlogn)
O
(
n
l
o
g
n
)
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 6e14
#define N 500010
inline char gc(){
static char buf[1<<16],*S,*T;
if(T==S){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=gc();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
return x*f;
}
int n,pa[N],fa[N],sz[N];
ll w[N],ans=0;
struct cmp{
bool operator()(int a,int b){return w[a]*sz[b]==w[b]*sz[a]?a<b:w[a]*sz[b]<w[b]*sz[a];}
};
set<int,cmp>st;
inline int find(int x){return x==pa[x]?x:pa[x]=find(pa[x]);}
int main(){
// freopen("a.in","r",stdin);
n=read();for(int i=1;i<=n;++i) pa[i]=i;
for(int i=1;i<=n;++i){
int x=read();fa[i]=x;int xx=find(x),yy=find(i);
if(xx==yy){puts("-1");return 0;}pa[xx]=yy;
}for(int i=1;i<=n;++i) w[i]=read(),sz[i]=1,st.insert(i),pa[i]=i;w[0]=inf;sz[0]=1;st.insert(0);pa[0]=0;
while(!st.empty()){
int x=*st.begin();if(!x) break;st.erase(x);
int y=find(fa[x]);st.erase(y);ans+=w[x]*sz[y];
pa[x]=y;w[y]+=w[x];sz[y]+=sz[x];st.insert(y);
}printf("%lld\n",ans);
return 0;
}