【AHOI2018】排列

题面

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);
}

猜你喜欢

转载自www.cnblogs.com/shxnb666/p/11427174.html