树的DFS序列就是说: 树的每一个节点在DFS中进出栈的时间序列。具体来说就是对树从根开始进行深搜,按搜到的时间顺序把所有节点排队。
上面这棵树,它的一个DFS序就是:1 4 6 6 3 9 9 3 4 7 7 2 5 5 8 8 2 1
注意两点:
①、一棵树的DFS序不唯一。
②、因为深搜的时候选择哪个子节点的顺序是不一样的。
对于一棵树进行DFS序,需要把回溯的时候的节点编号也记录一下,因此DFS序的长度是2N。
这就是为什么每个数字在DFS序中会出现两遍的原因。
性质 一个数字两次出现的位置所夹的区间,正好是以这个数为根的一个子树。
比如:
截取上面dfs序的2的两个位置的区间为:
2 8 8 5 5 2
那么2为根的子树是:2 8 5
经典用法:配合树状数组进行区间修改,单点查询
代码实现很简单,就是从根节点开始深搜,然后按顺序打标记就可以了。但是打标记的地方可以有很多:
⚪ id:DFS序列
⚪ in: 以u为根节点的子树的在dfs序列的起始位置。
⚪ out:以u为根节点的子树的在dfs序列的结束位置。
很明显,如果我们打了标记in和out,那么我们就能快速找到任何一棵子树。因为in[u]和out[u]的位置所夹的区间,正好是以这个数为根的一个子树。
vector<int> g[N];
int id[N],len;
int in[N],out[N];
void dfs(int u,int fa){
id[len++]=u;
in[u]=len;
for(int t:g[u]){
if(t!=fa) dfs(t,u);
}
out[u]=len;
}