题目描述:
树上有 $n$ 个节点,从 $0$ 到 $n-1$ , $parent[i]$ 是节点 $i$ 的父节点。根节点编号为 $0$ 。树节点的第 $k$ 个祖先是从该节点到根节点路径上的第 $k$ 个节点。
实现 TreeAncestor类:
- TreeAncestor(int n, int[] parent)对树和父数组中的节点数初始化对象。
- getKthAncestor(int node, int l)返回节点- node的第 $k$ 个祖先节点。如果不存在这样的祖先节点,返回 $-1$ 。
数据范围:
 $1\le k \le n \le 5\times 10^4$
至多查询 $5\times 10^4$
题解:
需要使用 $O(n\log n)$ 的做法,想到可以使用 $LCA$ 的树上倍增法。
使用 $fa[u][i]$ 表示 $u$ 节点向上爬 $2^i$ 层到达的节点,则 $fa[u][0] = parent[u]$ 。然后 $fa[u][i] = fa[fa[u][i-1]][i-1]$ 。先向上爬 $2^{i-1}$ 层,然后再向上爬 $2^{i-1}$ 层,利用了 $2^i = 2 ^ {i - 1} + 2^{i - 1}$ 。
加速操作:可以提前处理一个 $log2$ 数组 $log2[i] = \log2(i)$ , $log2[i] = log2[i >> 1] + 1$ 。
代码:
代码成了示例代码
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 
 | auto optimize_cpp_stdio = [](){
 std::ios::sync_with_stdio(false);
 std::cin.tie(nullptr);
 std::cout.tie(nullptr);
 return 0;
 }();
 class TreeAncestor
 {
 public:
 static const int maxn = 5e4 + 1;
 static const int maxm = 16;
 int fa[maxn][maxm] = {};
 int log2[maxn];
 TreeAncestor(int n, vector<int> &parent)
 {
 log2[0] = log2[1] = 0;
 for (int i = 2; i <= n; ++i)
 {
 log2[i] = log2[i >> 1] + 1;
 }
 for (int i = 0; i < n; ++i)
 {
 fa[i][0] = parent[i];
 }
 
 
 for (int j = 1; j < maxm; ++j)
 {
 for (int i = 0; i < n; ++i)
 {
 if (fa[i][j - 1] == -1)
 fa[i][j] = -1;
 else
 fa[i][j] = fa[fa[i][j - 1]][j - 1];
 }
 }
 }
 
 int getKthAncestor(int node, int k)
 {
 int tmp = log2[k], pa = node;
 while (k)
 {
 pa = fa[pa][tmp];
 if (pa == -1)
 break;
 k -= (1 << tmp);
 tmp = log2[k];
 }
 return pa;
 }
 };
 
 |