3067. Count Pairs of Connectable Servers in a Weighted Tree Network#
You are given a weighted tree without a root. The tree has a total of nodes, representing servers, numbered from to . You are also given an array , where represents a bidirectional edge between nodes and with a weight of . Additionally, you are given an integer .
If two servers , , and satisfy the following conditions, then we consider servers and to be connectable through server :
- , , and .
- The distance from to is divisible by .
- The distance from to is divisible by .
- The path from to does not share any common edges with the path from to .
Return an integer array of length , where represents the number of server pairs that are connectable through server .
Example 1:
Input: edges = [[0,1,1],[1,2,5],[2,3,13],[3,4,9],[4,5,2]], signalSpeed = 1
Output: [0,4,6,6,4,0]
Explanation: Since signalSpeed is equal to 1, count[c] is equal to the number of pairs of paths starting from c and having no common edges.
In the input graph, count[c] is equal to the product of the number of servers to the left of c and the number of servers to the right of c.
Example 2:
Input: edges = [[0,6,3],[6,5,3],[0,3,1],[3,2,7],[3,1,6],[3,4,2]], signalSpeed = 3
Output: [2,0,0,0,0,0,2]
Explanation: There are 2 connectable server pairs (4, 5) and (4, 6) through server 0.
There are 2 connectable server pairs (4, 5) and (0, 5) through server 6.
All other server pairs can only be connected through server 0 or 6, so the number of connectable server pairs for the other servers is 0.
Note:
- The input ensures that the form a valid tree.
Root Enumeration#
- , , and .
- The distance from to is divisible by .
- The distance from to is divisible by .
- The path from to does not share any common edges with the path from to .
From the conditions for connectivity, we can obtain the following information:
- The positions of and can be swapped, as long as there is a difference between them. (This can also be understood as preventing duplicates)
- is a node that divides the undirected acyclic graph into two parts, so that the path from to and the path from to do not share any common edges.
Analyze the following cases:
Traverse to subtree 1:
Traverse to subtree 2:
Traverse to subtree 3:
The sum of the results that satisfy the conditions for each traversal is the number of connectable node pairs for the current root node.
Code implementation:
class Solution {
public:
vector<int> countPairsOfConnectableServers(vector<vector<int>> &edges, int signalSpeed) {
int n = edges.size() + 1; // There is one less edge than the number of nodes
// {root, [<child1, cost1>, <child2, cost2>, ..., <childn, costn>]}
vector<vector<pair<int, int>>> graph(n);
for (const auto &edge : edges) {
graph[edge[0]].push_back({edge[1], edge[2]});
graph[edge[1]].push_back({edge[1], edge[2]});
}
/// @brief
/// @param root The root node, this parameter is passed in to prevent the root node of the subtree from going to this node
/// @param child Child node
/// @param remainder The distance from the root node to the child node
/// @return Returns the number of nodes in the subtree rooted at root, which satisfies that the path to reach it can be divided by signalSpeed
function<int(int, int, int)> dfs = [&](int root, int child, int remainder) -> int {
int res = 0;
if (remainder == 0) {
++res;
}
// Traverse all subtrees of the child node
for (const auto &[j, cost] : graph[child]) {
// Exclude the root node path
if (j != root) {
res += dfs(child, j, (remainder + cost) % signalSpeed);
}
}
return res;
};
vector<int> res(n);
// Traverse the root nodes
for (int i = 0; i < n; ++i) {
int pre = 0; // Count the number of connectable pairs of the subtree of the root node
// Traverse all subtrees of the root node
for (auto &[j, cost] : graph[i]) {
// The number of nodes that satisfy the current subtree
int cnt = dfs(i, j, cost % signalSpeed);
res[i] += pre * cnt;
pre += cnt;
}
}
return res;
}
};