( 数据结构专题 )【 dfs序 】
Dfs序是一棵树从根节点出发,dfs遍历时依次经过的节点序列。
作用:对于只对某个节点的 子树 进行操作时,可以将树简化为一维序列。
上面这个树的遍历顺序是:1 4 9 8 13 12 3 7 6 11 10 14 2 5
性质:对于一棵树的dfs序而言,同一棵子树所对应的点一定是dfs序中连续的一段。
这个性质非常重要,在利用dfs序来解题的过程中,这个不可缺少!
证明:在dfs遍历时,当进入一个节点之后,dfs会先把当前的节点的所有子节点都遍历一遍,然后在回溯到当前节点,在这个过程中,它的所有子孙节点一定都被访问过了,而且在这之前,它的任何一个子孙节点都不可能被访问过。然后它才离开当前子树,回到父亲节点,再访问其他子树,所以同一子树的节点在dfs序中一定是连续的一段。
实现
dfs,顺便记录下访问的顺序。设 dfn[u] = ++tim 为u是第 tim 个访问的节点。
那么怎么获取当前节点在dfs序中的范围呢?
我们引入sz[u] 表示u子树的节点数。
那么对于u节点,他的所有子节点的范围就是 [ dfn[u], dfn[u] + sz[u] - 1 ]
为了方便我们还可以引入rev[u] ,原节点编号的转换
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5+10;
struct node {
int to,nxt,w;
}e[maxn];
int dfn[maxn],sz[maxn],tim,rev[maxn];
int head[maxn],cnt,n;
void addage( int u, int v )
{
e[cnt].to = v;
e[cnt].nxt = head[u];
head[u] = cnt++;
}
void dfs( int u, int f )
{
dfn[u] = ++tim;
rev[tim] = u;
sz[u] = 1;
for ( int i=head[u]; i!=-1; i=e[i].nxt ) {
int v = e[i].to;
if ( v==f ) continue;
dfs(v,u);
sz[u] += sz[v];
}
}
int main()
{
memset(head,-1,sizeof(head));cnt=0;
cin>>n;
for ( int i=0; i<n-1; i++ ) {
int u,v;scanf("%d %d",&u,&v);
addage(u,v);addage(v,u);
}
dfs(1,1);
return 0;
}