乍一看我不会。

先不考虑加点。

先考虑没有那个除\(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;
}

51nod 1576 Tree and permutation(树的重心+dfn序)的更多相关文章

  1. POJ 2378 Tree Cutting (树的重心,微变形)

    题意: 给定一棵树,n个节点,若删除点v使得剩下的连通快最大都不超过n/2,则称这样的点满足要求.求所有这样的点,若没有这样的点,输出NONE. 思路: 只需要拿“求树的重心”的代码改一行就OK了.因 ...

  2. HDU6446 Tree and Permutation(树、推公式)

    题意: 给一棵N个点的树,对应于一个长为N的全排列,对于排列的每个相邻数字a和b,他们的贡献是对应树上顶点a和b的路径长,求所有排列的贡献和 思路: 对每一条边,边左边有x个点,右边有y个点,x+y= ...

  3. CF383C Propagating tree (线段树,欧拉序)

    \(tag\)没开够\(WA\)了一发... 求出\(dfs\)序,然后按深度分类更新与查询. #include <iostream> #include <cstdio> #i ...

  4. 洛谷P3703 [SDOI2017]树点涂色(LCT,dfn序,线段树,倍增LCA)

    洛谷题目传送门 闲话 这是所有LCT题目中的一个异类. 之所以认为是LCT题目,是因为本题思路的瓶颈就在于如何去维护同颜色的点的集合. 只不过做着做着,感觉后来的思路(dfn序,线段树,LCA)似乎要 ...

  5. POJ 2378.Tree Cutting 树形dp 树的重心

    Tree Cutting Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 4834   Accepted: 2958 Desc ...

  6. 51Nod 1737 配对(树的重心)

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1737 题意: 思路: 树的重心. 树的重心就是其所以子树的最大的子树结点 ...

  7. Codeforces Round #268 (Div. 1) 468D Tree(杜教题+树的重心+线段树+set)

    题目大意 给出一棵树,边上有权值,要求给出一个1到n的排列p,使得sigma d(i, pi)最大,且p的字典序尽量小. d(u, v)为树上两点u和v的距离 题解:一开始没看出来p需要每个数都不同, ...

  8. 点分治模板(洛谷P4178 Tree)(树分治,树的重心,容斥原理)

    推荐YCB的总结 推荐你谷ysn等巨佬的详细题解 大致流程-- dfs求出当前树的重心 对当前树内经过重心的路径统计答案(一条路径由两条由重心到其它点的子路径合并而成) 容斥减去不合法情况(两条子路径 ...

  9. POJ3107Godfather[树形DP 树的重心]

    Godfather Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 6121   Accepted: 2164 Descrip ...

随机推荐

  1. SQL Server UPDATE语句的用法详解

    SQL Server UPDATE语句用于更新数据,下面就为您详细介绍SQL Server UPDATE语句语法方面的知识,希望可以让您对SQL Server UPDATE语句有更多的了解. 现实应用 ...

  2. 安装ubuntu14.04之后要做的一些事

    前言: 用ubuntu14.04也有一段时间了,感觉与之前版本相比还是在挺多方面有了改进.但刚装完还是有一些小问题需要自己动手解决.鉴于网上的内容太过零碎,有些方案也太过老旧,因此在这里为大家总结一些 ...

  3. Flex简易教程

      常见的前端布局模型涵盖浮动.定位和弹性盒等 CSS 技术,其中浮动和定位技术往往在制作自适应布局页面时显得不够优雅--对于浮动布局,前后端分离时代很多时候我们并不知道每行会遍历显示多少个元素,每个 ...

  4. Project Euler 11 Largest product in a grid

    题意:在这个20×20方阵中,四个在同一方向(从下至上.从上至下.从右至左.从左至右或者对角线)上相邻的数的乘积最大是多少? 思路:暴力去枚举以 ( x , y ) 为中心拓展的四个方向 /***** ...

  5. mplayer 在线播放错误

    CPU: ARM Playing rtsp://admin:12345@192.168.1.198/mpeg4/main/ch01/av_stream.Connecting to server 192 ...

  6. 【codeforces 805C】Find Amir

    [题目链接]:http://codeforces.com/contest/805/problem/C [题意] 你能从任意一个位置i到达任意一个位置j; 花费为(i+j)%(n+1); 问你从任意一个 ...

  7. C#中的Attribute定义及用法

    1.Attribute定义 公共语言运行时允许添加类似关键字的描述声明,叫做attributes, 它对程序中的元素进行标注,如类型.字段.方法和属性等.Attributes和Microsoft .N ...

  8. BA--步进电机工作原理

    步进电机是将电脉冲信号转变为角位移或线位移的开环控制元步进电机件.在非超载的情况下,电机的转速.停止的位置只取决于脉冲信号的频率和脉冲数,而不受负载变化的影响,当步进驱动器接收到一个脉冲信号,它就驱动 ...

  9. CF894A QAQ

    CF894A QAQ 题意翻译 题目大意: 给定一个字符串,字符串长度<=100,现在要求出字符串中'QAQ'的个数,注意,'QAQ'可以不连续,只要有顺序就可以了,例如QABQ也有一个QAQ ...

  10. [Beginning SharePoint Designer 2010]Chapter2 编辑页面

    本章概要: 1.如何展开隐藏任务面板和ribbon标签 2.页面编辑模式 3.代码视图模式和智能提示 4.如何组合SharePoint和页面上其他元素