51nod 1576 Tree and permutation(树的重心+dfn序)
乍一看我不会。
先不考虑加点。
先考虑没有那个除\(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序)的更多相关文章
- POJ 2378 Tree Cutting (树的重心,微变形)
题意: 给定一棵树,n个节点,若删除点v使得剩下的连通快最大都不超过n/2,则称这样的点满足要求.求所有这样的点,若没有这样的点,输出NONE. 思路: 只需要拿“求树的重心”的代码改一行就OK了.因 ...
- HDU6446 Tree and Permutation(树、推公式)
题意: 给一棵N个点的树,对应于一个长为N的全排列,对于排列的每个相邻数字a和b,他们的贡献是对应树上顶点a和b的路径长,求所有排列的贡献和 思路: 对每一条边,边左边有x个点,右边有y个点,x+y= ...
- CF383C Propagating tree (线段树,欧拉序)
\(tag\)没开够\(WA\)了一发... 求出\(dfs\)序,然后按深度分类更新与查询. #include <iostream> #include <cstdio> #i ...
- 洛谷P3703 [SDOI2017]树点涂色(LCT,dfn序,线段树,倍增LCA)
洛谷题目传送门 闲话 这是所有LCT题目中的一个异类. 之所以认为是LCT题目,是因为本题思路的瓶颈就在于如何去维护同颜色的点的集合. 只不过做着做着,感觉后来的思路(dfn序,线段树,LCA)似乎要 ...
- POJ 2378.Tree Cutting 树形dp 树的重心
Tree Cutting Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 4834 Accepted: 2958 Desc ...
- 51Nod 1737 配对(树的重心)
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1737 题意: 思路: 树的重心. 树的重心就是其所以子树的最大的子树结点 ...
- Codeforces Round #268 (Div. 1) 468D Tree(杜教题+树的重心+线段树+set)
题目大意 给出一棵树,边上有权值,要求给出一个1到n的排列p,使得sigma d(i, pi)最大,且p的字典序尽量小. d(u, v)为树上两点u和v的距离 题解:一开始没看出来p需要每个数都不同, ...
- 点分治模板(洛谷P4178 Tree)(树分治,树的重心,容斥原理)
推荐YCB的总结 推荐你谷ysn等巨佬的详细题解 大致流程-- dfs求出当前树的重心 对当前树内经过重心的路径统计答案(一条路径由两条由重心到其它点的子路径合并而成) 容斥减去不合法情况(两条子路径 ...
- POJ3107Godfather[树形DP 树的重心]
Godfather Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 6121 Accepted: 2164 Descrip ...
随机推荐
- Vue学习之路第十三篇:v-for指令
v-for指令,看名字想必大家也能猜到其作用,没错,就是用来迭代.遍历的. 1.简单数组的遍历 <body> <divi id="app"> <spa ...
- UVA 12633 Super Rooks on Chessboard (生成函数+FFT)
题面传送门 题目大意:给你一张网格,上面有很多骑士,每个骑士能横着竖着斜着攻击一条直线上的格子,求没被攻击的格子的数量总和 好神奇的卷积 假设骑士不能斜着攻击 那么答案就是没被攻击的 行数*列数 接下 ...
- k8s的概念
Kubernetes(简称为 K8s),最初由 Google 的工程师开发和设计.Kubernetes 是用于自动部署.扩展和管理容器化应用程序的开源系统,它旨在提供跨主机集群的自动部署.扩展以及运行 ...
- C# 常用字符串加密解密方法
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Sec ...
- Elasticsearch架构原理
架构原理 本书作为 Elastic Stack 指南,关注于 Elasticsearch 在日志和数据分析场景的应用,并不打算对底层的 Lucene 原理或者 Java 编程做详细的介绍,但是 Ela ...
- 【树形DP】 HDU 2196 Computer
题意:求节点间的最大距离 先DFS一次 记录下 每一节点的子树下的最大距离(DP[ u ] [ 0 ])和第二大距离(DP[ u ] [ 1 ]) 用DP[ v ] [ 2 ] 表示由v的父节点来的最 ...
- 使用fatjar来实现将包括第三方jar包的项目到处成一个jar包供其它程序使用
一.在线安装fat jar 在线安装步骤: eclipse菜单条 help >software updates >Search for new features to install> ...
- Unity3D - 图形性能优化:优化着色器载入时间
Unity官方文档之"图形性能优化-优化着色器载入时间"的翻译,E文链接. Optimizing Shader Load Time 优化着色器载入时间 Shaders are sm ...
- 调用imagemagick做响应图片
设计出图后经常需要改下尺寸放在别的项目上使用,每次都是设计手工处理,其实图片服务可以做更多事情,比如借助强大的im,可以通过url控制图片尺寸 var childProcess = require(' ...
- Spork: Pig on Spark实现分析
介绍 Spork是Pig on Spark的highly experimental版本号,依赖的版本号也比較久,如之前文章里所说.眼下我把Spork维护在自己的github上:flare-spork. ...