节点爆裂后形成的子树
给你一棵具有特殊属性的n 叉树:如果我们破坏树的一个随机节点,该节点及其直接父节点直到根节点都会消失。这棵树有 N 个节点,节点编号从 1 到 N。根始终为 1。给定一个查询序列,表示我们开始爆裂的节点的编号,问题是找到将形成的子树的数量最后根据上面的属性,对每个查询独立进行。
例子:
Input:
Consider the following tree:
1
/ | \
2 3 4
/ \ \
5 6 7
/ \
8 9
q = 2
n = 1
n = 7
Output:
3
4
Explanation:
In the first query after bursting node 1, there
will be 3 subtrees formed rooted at 2, 3 and 4.
In the second query after bursting node 7, nodes
4 and 1 also get burst, thus there will
be 4 subtrees formed rooted at 8, 9, 2 and 3.
由于我们正在处理 n 叉树,我们可以使用类似于图的表示,并将双向边添加到列表数组中。现在,如果我们破坏一个节点,我们可以肯定地说它的所有子节点都将成为单独的子树。此外,其父母和其他祖先的所有孩子,直到根破裂,也将成为单独的子树。因此,在我们的最终答案中,我们希望排除当前节点及其在路径中的所有祖先,直到根。因此,我们可以形成方程来求解:
answer[node] = degree[node] + allChild[parent[node]] – countPath[node]
其中 allChild[]:节点的子节点数 + 其子节点数
父母的孩子 + ..+ 根的孩子的数量
parent[]:树中节点的父节点
degree[]:一个节点的子节点数
countPath[]:从根节点到父节点的节点数
我们可以在邻接列表上使用深度优先搜索来填充上述所有数组。我们可以从根 1 开始,假设其父级为 0,并递归深度优先将其值传播给其子级。因此,我们可以初步预处理和填充上述数组,并相应地为每个查询返回方程的值。
以下是上述方法的实现:
C++
// C++ program to find number of subtrees after bursting nodes
#include
using namespace std;
// do depth first search of node nod; par is its parent
void dfs(int nod, int par, list adj[], int allChild[],
int parent[], int degree[], int countPath[])
{
// go through the adjacent nodes
for (auto it = adj[nod].begin(); it != adj[nod].end(); it++) {
int curr = *it;
// avoid cycling
if (curr == par)
continue;
degree[nod]++;
countPath[curr] = countPath[nod] + 1;
parent[curr] = nod;
}
// propagated from parent
allChild[nod] = allChild[parent[nod]] + degree[nod];
// go through the adjacent nodes
for (auto it = adj[nod].begin(); it != adj[nod].end(); it++) {
int curr = *it;
// avoid cycling
if (curr == par)
continue;
// recur and go depth first
dfs(curr, nod, adj, allChild, parent, degree, countPath);
}
}
// Driver code
int main()
{
int n = 9;
// adjacency list for each node
list adj[n + 1];
// allChild[]: number of node's children + number of its
// parent's children + ..+ number of root's children
// parent[]: parent of a node in the tree
// degree[]: number of children for a node
// countPath[]: number of nodes from root to parent of node
int allChild[n + 1] = { 0 }, parent[n + 1] = { 0 },
degree[n + 1] = { 0 }, countPath[n + 1] = { 0 };
// construct tree
adj[1].push_back(2);
adj[2].push_back(1);
adj[1].push_back(3);
adj[3].push_back(1);
adj[1].push_back(4);
adj[4].push_back(1);
adj[3].push_back(5);
adj[5].push_back(3);
adj[3].push_back(6);
adj[6].push_back(3);
adj[4].push_back(7);
adj[7].push_back(4);
adj[7].push_back(8);
adj[8].push_back(7);
adj[7].push_back(9);
adj[9].push_back(7);
// assume 1 is root and 0 is its parent
dfs(1, 0, adj, allChild, parent, degree, countPath);
// 2 queries
int curr = 1;
cout << degree[curr] + allChild[parent[curr]] - countPath[curr] << endl;
curr = 7;
cout << degree[curr] + allChild[parent[curr]] - countPath[curr] << endl;
return 0;
}
Java
// Java program to find number of subtrees
// after bursting nodes
import java.util.*;
class GFG{
// Do depth first search of node nod;
// par is its parent
static void dfs(int nod, int par,
List adj[],
int allChild[],
int parent[],
int degree[],
int countPath[])
{
// Go through the adjacent nodes
for(int it : adj[nod])
{
int curr = it;
// astatic void cycling
if (curr == par)
continue;
degree[nod]++;
countPath[curr] = countPath[nod] + 1;
parent[curr] = nod;
}
// Propagated from parent
allChild[nod] = allChild[parent[nod]] +
degree[nod];
// Go through the adjacent nodes
for(int it : adj[nod])
{
int curr = it;
// astatic void cycling
if (curr == par)
continue;
// recur and go depth first
dfs(curr, nod, adj, allChild,
parent, degree, countPath);
}
}
// Driver code
public static void main(String[] args)
{
int n = 9;
// Adjacency list for each node
@SuppressWarnings("unchecked")
List []adj = new List[n + 1];
for(int i = 0; i < adj.length; i++)
adj[i] = new Vector();
// allChild[]: number of node's children +
// number of its parent's children + ..+
// number of root's children
// parent[]: parent of a node in the tree
// degree[]: number of children for a node
// countPath[]: number of nodes from root
// to parent of node
int []allChild = new int[n + 1];
int []parent = new int[n + 1];
int []degree = new int[n + 1];
int []countPath = new int[n + 1];
// Contree
adj[1].add(2);
adj[2].add(1);
adj[1].add(3);
adj[3].add(1);
adj[1].add(4);
adj[4].add(1);
adj[3].add(5);
adj[5].add(3);
adj[3].add(6);
adj[6].add(3);
adj[4].add(7);
adj[7].add(4);
adj[7].add(8);
adj[8].add(7);
adj[7].add(9);
adj[9].add(7);
// Assume 1 is root and 0 is its parent
dfs(1, 0, adj, allChild, parent,
degree, countPath);
// 2 queries
int curr = 1;
System.out.print(degree[curr] +
allChild[parent[curr]] -
countPath[curr] + "\n");
curr = 7;
System.out.print(degree[curr] +
allChild[parent[curr]] -
countPath[curr] + "\n");
}
}
// This code is contributed by Amit Katiyar
Python3
# Python3 program to find number of
# subtrees after bursting nodes
# Do depth first search of node
# nod par is its parent
def dfs(nod, par, adj, allChild,
parent, degree, countPath):
# Go through the adjacent nodes
for it in adj[nod]:
curr = it
# Avoid cycling
if (curr == par):
continue
degree[nod] += 1
countPath[curr] = countPath[nod] + 1
parent[curr] = nod
# Propagated from parent
allChild[nod] = (allChild[parent[nod]] +
degree[nod])
# Go through the adjacent nodes
for it in adj[nod]:
curr = it
# Avoid cycling
if (curr == par):
continue
# recur and go depth first
dfs(curr, nod, adj, allChild,
parent, degree, countPath)
# Driver code
if __name__ == '__main__':
n = 9
# Adjacency list for each node
adj = [[] for i in range(n + 1)]
# allChild: number of node's children + number of its
# parent's children + ..+ number of root's children
# parent: parent of a node in the tree
# degree: number of children for a node
# countPath: number of nodes from root to parent of node
allChild, parent = [0] * (n + 1), [0] * (n + 1)
degree, countPath = [0] * (n + 1), [0] * (n + 1)
# Construct tree
adj[1].append(2)
adj[2].append(1)
adj[1].append(3)
adj[3].append(1)
adj[1].append(4)
adj[4].append(1)
adj[3].append(5)
adj[5].append(3)
adj[3].append(6)
adj[6].append(3)
adj[4].append(7)
adj[7].append(4)
adj[7].append(8)
adj[8].append(7)
adj[7].append(9)
adj[9].append(7)
# Assume 1 is root and 0 is its parent
dfs(1, 0, adj, allChild, parent,
degree, countPath)
# 2 queries
curr = 1
print(degree[curr] + allChild[parent[curr]] -
countPath[curr])
curr = 7
print(degree[curr] + allChild[parent[curr]] -
countPath[curr])
# This code is contributed by mohit kumar 29
C#
// C# program to find number of subtrees
// after bursting nodes
using System;
using System.Collections.Generic;
class GFG{
// Do depth first search of node nod;
// par is its parent
static void dfs(int nod, int par,
List []adj,
int []allChild,
int []parent,
int []degree,
int []countPath)
{
// Go through the adjacent nodes
foreach(int it in adj[nod])
{
int curr = it;
// astatic void cycling
if (curr == par)
continue;
degree[nod]++;
countPath[curr] = countPath[nod] + 1;
parent[curr] = nod;
}
// Propagated from parent
allChild[nod] = allChild[parent[nod]] +
degree[nod];
// Go through the adjacent nodes
foreach(int it in adj[nod])
{
int curr = it;
// astatic void cycling
if (curr == par)
continue;
// recur and go depth first
dfs(curr, nod, adj, allChild,
parent, degree, countPath);
}
}
// Driver code
public static void Main(String[] args)
{
int n = 9;
// Adjacency list for each node
List []adj = new List[n + 1];
for(int i = 0; i < adj.Length; i++)
adj[i] = new List();
// allChild[]: number of node's children +
// number of its parent's children + ..+
// number of root's children
// parent[]: parent of a node in the tree
// degree[]: number of children for a node
// countPath[]: number of nodes from root
// to parent of node
int []allChild = new int[n + 1];
int []parent = new int[n + 1];
int []degree = new int[n + 1];
int []countPath = new int[n + 1];
// Contree
adj[1].Add(2);
adj[2].Add(1);
adj[1].Add(3);
adj[3].Add(1);
adj[1].Add(4);
adj[4].Add(1);
adj[3].Add(5);
adj[5].Add(3);
adj[3].Add(6);
adj[6].Add(3);
adj[4].Add(7);
adj[7].Add(4);
adj[7].Add(8);
adj[8].Add(7);
adj[7].Add(9);
adj[9].Add(7);
// Assume 1 is root and 0 is its parent
dfs(1, 0, adj, allChild, parent,
degree, countPath);
// 2 queries
int curr = 1;
Console.Write(degree[curr] +
allChild[parent[curr]] -
countPath[curr] + "\n");
curr = 7;
Console.Write(degree[curr] +
allChild[parent[curr]] -
countPath[curr] + "\n");
}
}
// This code is contributed by Amit Katiyar
Javascript
输出:
3
4
上述算法的时间复杂度为 O(E * lg(V)),其中 E id 是边数,V 是顶点数。