一、树的dfs序
1、思路
对数进行深度优先搜索时,对于每个节点,在刚进入递归后以及即将回溯前各记录一次该点的编号,最后产生的长度为2N的节点序列就为树的DFS序。——摘自算法竞赛进阶指南(李耀东)
2、性质
- 每个节点的编号出现两次,一次为 L [ x ] , R [ x ] L[x],R[x] L[x],R[x]。
- 闭区间 [ L [ x ] , R [ x ] ] [L[x],R[x]] [L[x],R[x]],就是以x为根的子树的DFS序。
3、Code
const int N = 1e5;
int a[N<<1],cnt = 0;//a记录dfs序
bool vis[N];
void dfs(int u){
a[++cnt] = u;
vis[x] = 1;
for(int i = head[u], ~i ;i = e[i].next){
int v = e[i].v;
if(vis[v]) continue;
dfs(v);
}
a[++cnt] = u;
}
二、树的深度
1、Code(自上而下)
const int N = 1e5;
int dis[N];//深度
void dfs(int u,int fa){
for(int i = head[u]; ~i ; i = next[i].next){
int v = e[i].v;
if(fa == v) continue;
dis[v] = dis[u] + 1;
dfs(v,u);
}
}
三、树的直径
1、思路
- 设两个 d p dp dp, d p 1 [ x ] dp1[x] dp1[x]是 x x x点到叶子结点的最长距离, d p 2 [ x ] dp2[x] dp2[x]是 x x x点到叶子结点的次长距离。
- 树的直径则为 d p 1 [ x ] + d p 2 [ x ] dp1[x]+dp2[x] dp1[x]+dp2[x]。
2、Code(自底而上)
const int N = 1e5+5;
int dp1[N],dp2[N],maxx = 0;//最大距离和次大距离,maxx树的直径
void dfs(int u,int fa){
for(int i = head[u]; ~i ; i = e[i].next){
int v = e[i].v;
if(v == fa) continue;
dfs(v,u);
if(dp1[u] < dp1[v] + 1){//更新最大距离
dp2[u] = dp1[u];
dp1[u] = dp1[v] + 1;
}
else if(dp2[u] < dp1[v] + 1){//更新次大距离
dp2[u] = dp1[v] + 1;
}
maxx = max(maxx,dp1[u]+dp2[u]);//树的直径
}
}
四、树的重心
1、定义
删除节点 x x x后产生的子树中,最大的一棵树的大小最小,则x称为树的重心。
2、思路
- 设每个节点 x x x为根的子树大小 s i z e [ x ] size[x] size[x],设节点 x x x的k个子节点为 y 1 − y 2 y1-y2 y1−y2, s i z e [ x ] = s i z e [ y 1 ] + s i z e [ y 2 ] + . . . . . . + s i z e [ y k ] + 1 size[x] = size[y1]+size[y2]+......+size[yk]+1 size[x]=size[y1]+size[y2]+......+size[yk]+1。
- 自底向上搜索,记录 x x x节点的子节点最大值max_part,并比较max_part与 n − s i z e [ x ] n-size[x] n−size[x](代表从整棵树中删去根节点为x的子树)的大小。
- 如果max_part小的话,就更新答案。
3、性质
- 树中所有点到某个点的距离和中,到重心的距离和是最小的,如果有两个距离和,他们的距离和一样。
- 把两棵树通过一条边相连,新树的重心在原来两棵树重心的连线上。
- 一棵树添加或删除一个节点,树的重心最多只移动一条边的位子。
- 一棵树最多有两个重心,且相邻。
4、Code(自底向上)
int size[N];
int n, ans, pos;//ans是max_part,pos是树的重心。
void dfs(int u,int fa){
size[u] = 1;
int max_part = 0;
for(int i = head[u]; ~i; i = e[i].next){
int v = e[i].v;
if(v == fa) continue;
dfs(v,u);
size[u] += size[v];//从子节点向父亲节点递推
max_part = max(max_part, size[v]);
}
max_part = max(max_part,n - size[u]);
if(max_part < ans){
ans = max_part;
pos = u;
}
}