Maximize the Number of Target Nodes After Connecting Trees I

medium tree bfs counting

Problem

You have two undirected trees: the first with n nodes (edges edges1) and the second with m nodes (edges edges2). A node u is target to v when the path between them has at most k edges (a node is always target to itself).

For every node i of the first tree you may add one edge from i to any node of the second tree (each query is independent). Return answer[i], the maximum number of nodes target to i.

The best move is fixed: count the nodes within distance k of i inside tree 1, then attach i to the tree-2 node whose ball of radius k−1 is largest. So answer[i] = within1(i, k) + maxv within2(v, k−1).

Inputedges1 = [[0,1],[0,2],[2,3],[2,4]], edges2 = [[0,1],[0,2],[0,3],[2,7],[1,4],[4,5],[4,6]], k = 2
Output[9,7,9,8,8]
The best tree-2 anchor reaches 4 nodes within distance k−1 = 1. For i = 0 the tree-1 ball within distance 2 holds 5 nodes, so 5 + 4 = 9.

def maxTargetNodes(edges1, edges2, k):
    def build(edges):                       # adjacency list + node count
        n = len(edges) + 1
        g = [[] for _ in range(n)]
        for a, b in edges:
            g[a].append(b)
            g[b].append(a)
        return g, n

    def reachable(g, n, src, limit):        # nodes within distance <= limit
        if limit < 0:
            return 0
        seen = [False] * n
        seen[src] = True
        q = deque([(src, 0)])
        cnt = 1
        while q:
            node, d = q.popleft()
            if d == limit:                  # ball edge: do not expand
                continue
            for nb in g[node]:
                if not seen[nb]:
                    seen[nb] = True
                    cnt += 1
                    q.append((nb, d + 1))
        return cnt

    g1, n = build(edges1)
    g2, m = build(edges2)

    best2 = 0                               # best tree-2 anchor (radius k-1)
    for v in range(m):
        best2 = max(best2, reachable(g2, m, v, k - 1))

    ans = []
    for i in range(n):                      # tree-1 ball (radius k) + best2
        ans.append(reachable(g1, n, i, k) + best2)
    return ans
function maxTargetNodes(edges1, edges2, k) {
  function build(edges) {                    // adjacency list + node count
    const n = edges.length + 1;
    const g = Array.from({ length: n }, () => []);
    for (const [a, b] of edges) {
      g[a].push(b);
      g[b].push(a);
    }
    return [g, n];
  }
  function reachable(g, n, src, limit) {      // nodes within distance <= limit
    if (limit < 0) return 0;
    const seen = new Array(n).fill(false);
    seen[src] = true;
    const q = [[src, 0]];
    let cnt = 1;
    for (let h = 0; h < q.length; h++) {
      const [node, d] = q[h];
      if (d === limit) continue;             // ball edge: do not expand
      for (const nb of g[node]) {
        if (!seen[nb]) {
          seen[nb] = true;
          cnt++;
          q.push([nb, d + 1]);
        }
      }
    }
    return cnt;
  }
  const [g1, n] = build(edges1);
  const [g2, m] = build(edges2);
  let best2 = 0;                             // best tree-2 anchor (radius k-1)
  for (let v = 0; v < m; v++) {
    best2 = Math.max(best2, reachable(g2, m, v, k - 1));
  }
  const ans = [];
  for (let i = 0; i < n; i++) {              // tree-1 ball (radius k) + best2
    ans.push(reachable(g1, n, i, k) + best2);
  }
  return ans;
}
int[] maxTargetNodes(int[][] edges1, int[][] edges2, int k) {
    List<List<Integer>> g1 = build(edges1);   // adjacency lists
    List<List<Integer>> g2 = build(edges2);
    int n = g1.size(), m = g2.size();
    int best2 = 0;                            // best tree-2 anchor (radius k-1)
    for (int v = 0; v < m; v++) {
        best2 = Math.max(best2, reachable(g2, v, k - 1));
    }
    int[] ans = new int[n];
    for (int i = 0; i < n; i++) {             // tree-1 ball (radius k) + best2
        ans[i] = reachable(g1, i, k) + best2;
    }
    return ans;
}

List<List<Integer>> build(int[][] edges) {
    int n = edges.length + 1;
    List<List<Integer>> g = new ArrayList<>();
    for (int i = 0; i < n; i++) g.add(new ArrayList<>());
    for (int[] e : edges) { g.get(e[0]).add(e[1]); g.get(e[1]).add(e[0]); }
    return g;
}

int reachable(List<List<Integer>> g, int src, int limit) {
    if (limit < 0) return 0;
    int n = g.size();
    boolean[] seen = new boolean[n];
    seen[src] = true;
    Deque<int[]> q = new ArrayDeque<>();
    q.add(new int[]{src, 0});
    int cnt = 1;
    while (!q.isEmpty()) {
        int[] cur = q.poll();
        if (cur[1] == limit) continue;        // ball edge: do not expand
        for (int nb : g.get(cur[0])) {
            if (!seen[nb]) {
                seen[nb] = true;
                cnt++;
                q.add(new int[]{nb, cur[1] + 1});
            }
        }
    }
    return cnt;
}
vector<int> maxTargetNodes(vector<vector<int>>& edges1,
                           vector<vector<int>>& edges2, int k) {
    auto build = [](vector<vector<int>>& edges) {   // adjacency list
        int n = edges.size() + 1;
        vector<vector<int>> g(n);
        for (auto& e : edges) { g[e[0]].push_back(e[1]); g[e[1]].push_back(e[0]); }
        return g;
    };
    auto reachable = [](vector<vector<int>>& g, int src, int limit) {
        if (limit < 0) return 0;
        int n = g.size();
        vector<char> seen(n, 0);
        seen[src] = 1;
        queue<pair<int,int>> q;
        q.push({src, 0});
        int cnt = 1;
        while (!q.empty()) {
            auto [node, d] = q.front(); q.pop();
            if (d == limit) continue;              // ball edge: do not expand
            for (int nb : g[node]) {
                if (!seen[nb]) {
                    seen[nb] = 1;
                    cnt++;
                    q.push({nb, d + 1});
                }
            }
        }
        return cnt;
    };
    vector<vector<int>> g1 = build(edges1), g2 = build(edges2);
    int n = g1.size(), m = g2.size();
    int best2 = 0;                                 // best tree-2 anchor (k-1)
    for (int v = 0; v < m; v++)
        best2 = max(best2, reachable(g2, v, k - 1));
    vector<int> ans(n);
    for (int i = 0; i < n; i++)                     // tree-1 ball (k) + best2
        ans[i] = reachable(g1, i, k) + best2;
    return ans;
}
Time: O((n + m) · (n + m)) Space: O(n + m)