📌  相关文章
📜  用于 Q 查询的子树中距 S 距离 K 处的节点计数

📅  最后修改于: 2022-05-13 01:56:09.580000             🧑  作者: Mango

用于 Q 查询的子树中距 S 距离 K 处的节点数

给定一棵由N个节点组成并以节点1为根的树,还给定一个由M对组成的数组Q[] ,其中每个数组元素表示一个(S, K)形式的查询。任务是为数组的每个查询(S, K)打印节点S的子树中距离K处的节点数。

例子:

朴素方法:最简单的方法是让每个查询从节点S运行深度优先搜索(DFS),并找到与给定节点S距离为K的所有节点。

时间复杂度: O(N*Q)
辅助空间: O(1)

有效方法:上述方法可以根据以下观察进行优化:

请按照以下步骤解决问题:

  • 初始化三个数组,比如tin[]tout[]depth[]来分别存储节点的进入时间、退出时间和深度。
  • 初始化两个 2D 向量,比如adjlevels ,以存储每个节点在特定深度的邻接列表和进入时间。
  • 初始化一个变量,比如t1,以跟踪时间。
  • 定义一个递归 DFS函数,比如dfs(node, parent, d) ,并执行以下步骤:
    • t分配给tin[node] ,然后将t1。
    • tin[node]推入向量levels[d]中,然后将d分配给depth[node]。
    • 遍历节点的子节点,并将递归函数调用为每个子节点 X 的dfs(X, node, d+1)
    • 完成上述步骤后,将t赋值给tout[node]并将t1。
  • 调用递归函数dfs(1, 1, 0)。
  • 使用变量i遍历数组Q[]并执行以下操作:
    • 将当前数组元素的值存储为S = Q [i].first 和K = Q[i].second。
    • 在向量levels[depth[S]+K]中找到所有大于tin[S]的节点的计数,并将其存储在变量L中。
    • 在向量级别[depth[S]+K]中找到所有大于tout[S]的节点的计数,并将其存储在变量R中。
    • 打印RL的值作为当前查询的答案。

下面是上述方法的实现:

C++
// C++ program for the above approach
#include 
using namespace std;
 
int tin[100], tout[100], depth[100];
int t = 0;
 
// Function to add edges
void Add_edge(int parent, int child,
              vector >& adj)
{
    adj[parent].push_back(child);
    adj[child].push_back(parent);
}
 
// Function to perform Depth First Search
void dfs(int node, int parent, vector >& adj,
         vector >& levels, int d)
{
    // Stores the entry time of a node
    tin[node] = t++;
 
    // Stores the entering time
    // of a node at depth d
    levels[d].push_back(tin[node]);
    depth[node] = d;
 
    // Iterate over the children of node
    for (auto x : adj[node]) {
        if (x != parent)
            dfs(x, node, adj, levels, d + 1);
    }
 
    // Stores the Exit time of a node
    tout[node] = t++;
}
 
// Function to find number of nodes
// at distance K from node S in the
// subtree of S
void numberOfNodes(int node, int dist,
                   vector >& levels)
{
    // Distance from root node
    dist += depth[node];
 
    // Index of node with greater tin value
    // then tin[S]
    int start = lower_bound(levels[dist].begin(),
                            levels[dist].end(), tin[node])
                - levels[dist].begin();
 
    // Index of node with greater tout value then tout[S]
    int ed = lower_bound(levels[dist].begin(),
                         levels[dist].end(), tout[node])
             - levels[dist].begin();
 
    // Answer to the Query
    cout << ed - start << endl;
}
 
// Function for performing DFS
// and answer to queries
void numberOfNodesUtil(pair Q[], int M, int N)
{
 
    vector > adj(N + 5), levels(N + 5);
 
    Add_edge(1, 2, adj);
    Add_edge(1, 3, adj);
    Add_edge(2, 4, adj);
    Add_edge(2, 5, adj);
    Add_edge(2, 6, adj);
 
    t = 1;
 
    // DFS function call
    dfs(1, 1, adj, levels, 0);
 
    // Traverse the array Q[]
    for (int i = 0; i < M; ++i) {
        numberOfNodes(Q[i].first, Q[i].second, levels);
    }
}
 
// Driver Code
int main()
{
    // Input
    int N = 6;
    pair Q[] = { { 2, 1 }, { 1, 1 } };
    int M = sizeof(Q) / sizeof(Q[0]);
 
    // Function call
    numberOfNodesUtil(Q, M, N);
}


Python3
# Python3 program for the above approach
from bisect import bisect_left, bisect_right
 
tin = [0] * 100
tout = [0] * 100
depth = [0] * 100
t = 0
 
# Function to add edges
def Add_edge(parent, child, adj):
     
    adj[parent].append(child)
    adj[child].append(parent)
    return adj
 
# Function to perform Depth First Search
def dfs(node, parent, d):
     
    global tin, tout, depth, adj, levels, t
     
    # Stores the entry time of a node
    tin[node] = t
    t += 1
 
    # Stores the entering time
    # of a node at depth d
    levels[d].append(tin[node])
    depth[node] = d
 
    # Iterate over the children of node
    for x in adj[node]:
        if (x != parent):
            dfs(x, node, d + 1)
 
    # Stores the Exit time of a node
    tout[node] = t
    t += 1
 
# Function to find number of nodes
# at distance K from node S in the
# subtree of S
def numberOfNodes(node, dist):
     
    global levels, tin, tout
     
    # Distance from root node
    dist += depth[node]
 
    # Index of node with greater tin value
    # then tin[S]
    start = bisect_left(levels[dist], tin[node])
 
    # Index of node with greater tout value then tout[S]
    ed = bisect_left(levels[dist], tout[node])
 
    # Answer to the Query
    print(ed - start)
 
# Function for performing DFS
# and answer to queries
def numberOfNodesUtil(Q, M, N):
     
    global t, adj
 
    adj = Add_edge(1, 2, adj)
    adj = Add_edge(1, 3, adj)
    adj = Add_edge(2, 4, adj)
    adj = Add_edge(2, 5, adj)
    adj = Add_edge(2, 6, adj)
 
    t = 1
 
    # DFS function call
    dfs(1, 1, 0)
 
    # Traverse the array Q[]
    for i in range(M):
        numberOfNodes(Q[i][0], Q[i][1])
 
# Driver Code
if __name__ == '__main__':
     
    # Input
    N = 6
    Q = [ [ 2, 1 ], [ 1, 1 ] ]
 
    M = len(Q)
 
    adj = [[] for i in range(N+5)]
    levels = [[] for i in range(N + 5)]
 
    # Function call
    numberOfNodesUtil(Q, M, N)
 
# This code is contributed by mohit kumar 29


输出
3
2

时间复杂度: O(N + M*log(N))
辅助空间: O(N)