Maximum Number of K-Divisible Components

hard tree DFS subtree sum

Problem

An undirected tree has n nodes (labels 0..n−1) with the given edges, a node-value array values, and an integer k. A valid split removes any set of edges so every resulting connected component has a node-value sum divisible by k. Return the maximum number of components over all valid splits. The total of values is guaranteed divisible by k.

Inputn = 5, edges = [[0,2],[1,2],[1,3],[2,4]], values = [1,8,1,4,4], k = 6
Output2
Cut the edge 1–2. Component {1,3} sums to 8+4 = 12 (÷6), component {0,2,4} sums to 1+1+4 = 6 (÷6). No split yields more than 2 components.

def maxKDivisibleComponents(n, edges, values, k):
    g = [[] for _ in range(n)]            # adjacency list
    for a, b in edges:
        g[a].append(b)
        g[b].append(a)
    count = 0

    def dfs(u, parent):
        nonlocal count
        s = values[u] % k                 # this node's residue
        for v in g[u]:
            if v != parent:
                s += dfs(v, u)            # add child subtree residue
        if s % k == 0:
            count += 1                    # cut off: own component
            return 0                      # contributes 0 to parent
        return s % k                      # carry residue up to parent

    dfs(0, -1)                            # root the tree at node 0
    return count
function maxKDivisibleComponents(n, edges, values, k) {
  const g = Array.from({ length: n }, () => []); // adjacency list
  for (const [a, b] of edges) { g[a].push(b); g[b].push(a); }
  let count = 0;

  function dfs(u, parent) {
    let s = values[u] % k;                // this node's residue
    for (const v of g[u]) {
      if (v !== parent) s += dfs(v, u);   // add child subtree residue
    }
    if (s % k === 0) {
      count++;                            // cut off: own component
      return 0;                           // contributes 0 to parent
    }
    return s % k;                         // carry residue up to parent
  }

  dfs(0, -1);                             // root the tree at node 0
  return count;
}
int count = 0;
public int maxKDivisibleComponents(int n, int[][] edges, int[] values, int k) {
    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]); }
    dfs(0, -1, g, values, k);             // root the tree at node 0
    return count;
}

private long dfs(int u, int parent, List<List<Integer>> g, int[] values, int k) {
    long s = values[u] % k;               // this node's residue
    for (int v : g.get(u)) {
        if (v != parent) s += dfs(v, u, g, values, k); // child residue
    }
    if (s % k == 0) {
        count++;                          // cut off: own component
        return 0;                         // contributes 0 to parent
    }
    return s % k;                         // carry residue up to parent
}
int maxKDivisibleComponents(int n, vector<vector<int>>& edges, vector<int>& values, int k) {
    vector<vector<int>> g(n);              // adjacency list
    for (auto& e : edges) { g[e[0]].push_back(e[1]); g[e[1]].push_back(e[0]); }
    int count = 0;

    function<long long(int,int)> dfs = [&](int u, int parent) -> long long {
        long long s = values[u] % k;      // this node's residue
        for (int v : g[u])
            if (v != parent) s += dfs(v, u); // add child subtree residue
        if (s % k == 0) {
            count++;                      // cut off: own component
            return 0LL;                   // contributes 0 to parent
        }
        return s % k;                     // carry residue up to parent
    };

    dfs(0, -1);                           // root the tree at node 0
    return count;
}
Time: O(n) Space: O(n)