题面
https://www.luogu.org/problem/P4437
题解
先把依赖关系形成的数建出来。
化一下那个式子,再作差比较一下,发现就是找平均值最大的一段。
然后用线段树维护最大值和单点修改(删除操作),删除一个点就直接把他的儿子接到它父亲上。
细节记得不太清楚了。
#include<cstdio> #include<iostream> #include<algorithm> #include<vector> #include<queue> #define ri register int #define N 500050 #define ll long long #define inf 987654321*987654321LL using namespace std; int n; ll w[N],tot[N],a[N],fa[N],siz[N]; bool used[N],del[N]; vector<ll> back[N]; struct segment_tree{ ll tt[4*N]; void maketree(int x,int l,int r){ if (l==r) { tt[x]=l; return; } int mid=(l+r)>>1; maketree(x<<1,l,mid); maketree(x<<1|1,mid+1,r); if (w[tt[x<<1]]<=w[tt[x<<1|1]]) tt[x]=tt[x<<1]; else tt[x]=tt[x<<1|1]; } int query() { return tt[1]; } void update(int x,int loc,int l,int r) { if (l==r) { tt[x]=l; return; } int mid=(l+r)>>1; if (loc<=mid) update(x<<1,loc,l,mid); else update(x<<1|1,loc,mid+1,r); if (w[tt[x<<1]]/((long double)siz[tt[x<<1]])<w[tt[x<<1|1]]/((long double)siz[tt[x<<1|1]]*1.0)) tt[x]=tt[x<<1]; else tt[x]=tt[x<<1|1]; } } yy; int main() { scanf("%d",&n); for (ri i=1;i<=n;i++) { scanf("%lld",&a[i]); if (a[i]) { back[a[i]].push_back(i); fa[i]=a[i]; } } for (ri i=1;i<=n;i++) { scanf("%lld",&w[i]); tot[i]=w[i]; siz[i]=1; } ll ans=0,cnt=0; yy.maketree(1,1,n); for (ri i=1;i<=n;i++) used[i]=0; used[0]=1; for (ri i=1;i<=n;i++) { int now=yy.query(); if (used[fa[now]]) { ans+=cnt*w[now]+tot[now]; cnt+=siz[now]; used[now]=1; w[now]=inf; siz[now]=1; yy.update(1,now,1,n); } else { del[now]=1; for (ri j=back[now].size()-1;j>=0;j--) if (!del[back[now][j]])fa[back[now][j]]=fa[now],back[fa[now]].push_back(back[now][j]); tot[fa[now]]=tot[fa[now]]+siz[fa[now]]*w[now]+tot[now]; siz[fa[now]]+=siz[now]; w[fa[now]]+=w[now]; yy.update(1,fa[now],1,n); w[now]=inf; siz[now]=1; yy.update(1,now,1,n); } } if (ans==0) puts("-1"); else printf("%lld",ans); }