树的DFS

树的DFS

给定一棵 $n$ 个节点的树。

节点的编号为 $1 \sim n$,其中 $1$ 号节点为根节点,每个节点的编号都大于其父节点的编号。

现在,你需要回答 $q$ 个询问。

每个询问给定两个整数 $u_{i},k_{i}$。

我们希望你用 DFS(深度优先搜索)算法来遍历根节点为 $u_{i}$ 的子树。

我们规定,当遍历(或回溯)到某一节点时,下一个遍历的目标应该是它的未经遍历的子节点中编号最小的那一个子节点。

例如,上图实例中:

  • 如果遍历根节点为 $1$ 号节点的子树,则子树内各节点的遍历顺序为 $\left[ {1,2,3,5,6,8,7,9,4} \right]$。
  • 如果遍历根节点为 $3$ 号节点的子树,则子树内各节点的遍历顺序为 $\left[ {3,5,6,8,7,9} \right]$。
  • 如果遍历根节点为 $7$ 号节点的子树,则子树内各节点的遍历顺序为 $\left[ {7,9} \right]$。
  • 如果遍历根节点为 $9$ 号节点的子树,则子树内各节点的遍历顺序为 $\left[ {9} \right]$。

每个询问就是让你计算采用规定的 DFS 算法来遍历根节点为 $u_{i}$ 的子树时,第 $k_{i}$ 个被遍历到的节点的编号。

输入格式

第一行包含两个整数 $n,q$。

第二行包含 $n−1$ 个整数 $p_{2},p_{3},…,p_{n}$,其中 $p_{i}$ 表示第 $i$ 号节点的父节点的编号。

接下来 $q$ 行,每行包含两个整数 $u_{i},k_{i}$,表示一组询问。

输出格式

共 $q$ 行,每组询问输出一行一个整数表示第 $k_{i}$ 个被遍历到的节点的编号。

如果第 $k_{i}$ 个被遍历到的节点不存在,则输出 $−1$。

数据范围

前三个测试点满足 $2 \leq n \leq 20$,$1 \leq q \leq 20$。
所有测试点满足 $2 \leq n \leq 2 \times {10}^{5}$,$1 \leq q \leq 2 \times {10}^{5}$,$1 \leq p_{i} < i$,$1 \leq u_{i},k_{i} \leq n$。

输入样例:

9 6
1 1 1 3 5 3 5 7
3 1
1 5
3 4
7 3
1 8
1 9

输出样例:

3
6
8
-1
9
4

 

解题思路

  这题还是很简单的,不过因为周赛第一题看错题意,结果卡了40分钟,最后来不及写完这题。

  题目就是问一棵树深度优先遍历的序列。然后给的一个结点编号,求以这个结点为子树的深度优先遍历序列的第$k$个结点。

  可以发现,每一棵子树在dfs序列中,一定是连续的一段。

  因此,先将整棵树的dfs序列求出来,然后求以$u$为根节点的子树的dfs序列中的第$k$个结点,这个序列一定是$u$后面连续的一段,如果$k$大于这个子树的大小,则无解。

  AC代码如下:

 1 #include <cstdio>
 2 #include <vector>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 const int N = 2e5 + 10;
 7 
 8 vector<int> graph[N];
 9 int order[N], h[N], cnt;    // order存放dfs序列,h是每个结点在order中的下标映射
10 int sum[N];     // sum存放每个以结点为子树的大小
11 
12 int dfs(int src) {
13     order[cnt] = src;
14     h[src] = cnt++;
15     sum[src] = 1;
16     
17     for (auto &it : graph[src]) {
18         sum[src] += dfs(it);
19     }
20     
21     return sum[src];
22 }
23 
24 int main() {
25     int n, m;
26     scanf("%d %d", &n, &m);
27     for (int i = 2; i <= n; i++) {
28         int root;
29         scanf("%d", &root);
30         graph[root].push_back(i);
31     }
32     
33     dfs(1);
34     
35     while (m--) {
36         int u, k;
37         scanf("%d %d", &u, &k);
38         if (k > sum[u]) printf("-1\n");
39         else printf("%d\n", order[h[u] + k - 1]);
40     }
41     
42     return 0;
43 }

 

参考资料

  DFS序列:https://www.acwing.com/video/3723/

posted @ 2022-03-06 11:13  onlyblues  阅读(260)  评论(0编辑  收藏  举报
Web Analytics