乍一看我不会。

先不考虑加点。

先考虑没有那个除\(2\)。

考虑每一条边的贡献,假设某一条边把这棵树分成大小为x,y的两个部分。

那么这条边最多可以被使用\(min(x,y)*2\)次(因为有进有出),即贡献最大为\(min(x,y)*2*\)这条边的权值。

那么能不能让每一条边的被使用达到最大呢?

显然可以。

那怎么快速算这个东西呢?不可能每加一个点就dfs一遍吧。那样就\(T\)飞了。

实际上这个东西就是每个点到树的重心的距离\(*2\)。

为什么?因为满足以树的重心为根每一个子树大小\(<\)总共的节点数。每一棵子树内所有点都要向子树外也就是根(重心)连边。

然后发现这个除\(2\)没有向下取整。

所以就是求所有的点到重心的距离和。

然后加点的话可以离线然后\(dfn序\)维护一下。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define ls now<<1
#define rs now<<1|1
const int N=101000;
int cnt,head[N];
struct edge{
int to,nxt;
}e[N*2];
void add_edge(int u,int v){
cnt++;
e[cnt].nxt=head[u];
e[cnt].to=v;
head[u]=cnt;
}
int size[N],fa[N][22],dep[N],dfn[N],tot;
void dfs(int u,int f){
size[u]=1;
dfn[u]=++tot;
fa[u][0]=f;dep[u]=dep[f]+1;
for(int i=1;i<=20;i++)fa[u][i]=fa[fa[u][i-1]][i-1];
int maxson=-1;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(v==f)continue;
dfs(v,u);
size[u]+=size[v];
}
}
int getlca(int x,int y){
if(dep[x]<dep[y])swap(x,y);
for(int i=20;i>=0;i--)
if(dep[fa[x][i]]>=dep[y])x=fa[x][i];
if(x==y)return x;
for(int i=20;i>=0;i--)
if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
int sum[N*4];
void update(int now){
sum[now]=sum[ls]+sum[rs];
}
void build(int l,int r,int now){
if(l==r){
if(l==1)sum[l]=1;
return ;
}
int mid=(l+r)>>1;
build(l,mid,ls);
build(mid+1,r,rs);
update(now);
}
void add(int l,int r,int x,int now){
if(l==r){
sum[now]=1;
return;
}
int mid=(l+r)>>1;
if(x>mid)add(mid+1,r,x,rs);
else add(l,mid,x,ls);
update(now);
}
int check(int l,int r,int L,int R,int now){
if(l==L&&r==R)return sum[now];
int mid=(l+r)>>1;
if(L>mid)return check(mid+1,r,L,R,rs);
else if(R<=mid)return check(l,mid,L,R,ls);
else return check(l,mid,L,mid,ls)+check(mid+1,r,mid+1,R,rs);
}
int up(int x,int y){
for(int i=20;i>=0;i--)
if(dep[fa[x][i]]>dep[y])x=fa[x][i];
return x;
}
int read(){
int sum=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
return sum*f;
}
int n,root;
long long ans;
int main(){
n=read();n++;
root=1;ans=0;
for(int i=2;i<=n;i++){
int v=read();
add_edge(i,v);add_edge(v,i);
}
dfs(1,0);
build(1,n,1);
for(int i=2;i<=n;i++){
add(1,n,dfn[i],1);
int lca=getlca(root,i);
ans+=(long long)(dep[root]+dep[i]-2ll*dep[lca]);
if(lca==root){
int x=up(i,root);
int sizex=check(1,n,dfn[x],dfn[x]+size[x]-1,1);
if(sizex>i-sizex)root=x,ans+=(long long)(i-sizex*2ll);
}
else{
int x=fa[root][0];
int sizex=check(1,n,dfn[root],dfn[root]+size[root]-1,1);
if(i-sizex>sizex)root=x,ans+=(long long)(sizex*2ll-i);
}
printf("%lld\n",ans);
}
return 0;
}

最新文章

  1. C#教程(1) -- .Net与C#简介
  2. 批量Ping IP
  3. 1051 Wooden Sticks
  4. linux bash shell中case语句的实例
  5. [RxJS] Starting a Stream with SwitchMap &amp; switchMapTo
  6. 解决本地访问Android文档是非常慢的问题
  7. 有向图的邻接矩阵表示法(创建,DFS,BFS)
  8. 程序员也是弱势群体?——从WePhone开发者事件说起
  9. 这个接口管理平台 eoLinker 开源版部署指南你一定不想错过
  10. windows的服务中的登录身份本地系统账户、本地服务账户和网络服务账户修改
  11. #ifndef, #define, #endif 作用
  12. 初窥css---选择器及相关特性
  13. 3.3.1 MyBatis框架介绍
  14. 多线程系列之十:Future模式
  15. 使用nginx作为webservice接口代理
  16. 排序算法(9)--Distribution Sorting--分布排序[1]--Counting sort--计数器排序
  17. canvas实例_时钟
  18. Daily Scrum NO.6
  19. Delphi下让窗口不显示在任务栏的另类方法
  20. node系列:全局与本地

热门文章

  1. sessionStorage缓存滚动条位置
  2. ELO kernels 记录
  3. HDU1846 - Brave Game【巴什博弈】
  4. 【Codeforces 469B】Chat Online
  5. Ajax发送简单请求案例
  6. mysql安装出错cannot create windows service for mysql.error:0
  7. Android应用之——自己定义控件ToggleButton
  8. BZOJ 2124: 等差子序列 线段树维护hash
  9. 转:Centos 7 使用git 用 ssh 连接github服务器
  10. Django迁移到mysql数据库时的错误