2020 CCPC-Wannafly Winter Camp Day2 (Div.1&2) E. 阔力梯的树

启发式合并即可

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb push_back
vector<int>v[N];
int n,sz[N];
void dfs(int now){
  sz[now]=1;
  for(auto k:v[now]){
    dfs(k);
    sz[now]+=sz[k];
  }
}
LL ans[N],MAX=1e18,MIN=-1e18;
int num[N];
set<LL>fu[N];
void merge(int x,int y){
  for(auto k:fu[y]){
    if(k==MAX||k==MIN)
      continue;
    auto ne=--fu[x].upper_bound(k);
    auto f=fu[x].upper_bound(k);
    if(*f==MAX){
      if(*ne!=MIN){
        ans[x]+=(k-*ne)*(k-*ne);
      }
    }else{
      if(*ne==MIN){
        ans[x]+=(*f-k)*(*f-k);
      }else{
        ans[x]-=(*f-*ne)*(*f-*ne);
        ans[x]+=(*f-k)*(*f-k);
        ans[x]+=(k-*ne)*(k-*ne);
      }
    }
    fu[x].insert(k);
  }
}
LL ok[N];
void gao(int now){
  fu[now].insert(now);
  for(auto k:v[now]){
    gao(k);
    int x=num[now];
    int y=num[k];
    if(fu[x].size()>=fu[y].size()){
      merge(x,y);
      fu[y].clear();
    }else{
      merge(y,x);
      fu[x].clear();
      swap(num[k],num[now]);
    }
  }
  ok[now]=ans[num[now]];
}
int main() {
  scanf("%d",&n);
  for(int i=1;i<=n;i++){
    num[i]=i;
    fu[i].insert(MAX);
    fu[i].insert(MIN);
  }
  for(int i=2;i<=n;i++){
    int x;
    scanf("%d",&x);
    v[x].pb(i);
  }
  dfs(1);
  gao(1);
  for(int i=1;i<=n;i++){
    printf("%lld\n",ok[i]);
  }
  return 0;
}
全部评论

相关推荐

点赞 评论 收藏
分享
10-09 09:39
门头沟学院 C++
HHHHaos:这也太虚了,工资就一半是真的
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务