|
1 | 1 | package Solution
|
2 | 2 |
|
3 |
| -func Solution(x bool) bool { |
4 |
| - return x |
| 3 | +import ( |
| 4 | + "math" |
| 5 | + "sort" |
| 6 | +) |
| 7 | + |
| 8 | +// minimumScore calculates the minimum score achievable by removing two distinct edges from a tree. |
| 9 | +// The score is defined as the difference between the largest and smallest XOR values of the three resulting components. |
| 10 | +func Solution(nums []int, edges [][]int) int { |
| 11 | + n := len(nums) // Number of nodes |
| 12 | + |
| 13 | + // 1. Build adjacency list for graph traversal |
| 14 | + adj := make([][]int, n) |
| 15 | + for _, edge := range edges { |
| 16 | + u, v := edge[0], edge[1] |
| 17 | + adj[u] = append(adj[u], v) |
| 18 | + adj[v] = append(adj[v], u) // Undirected graph |
| 19 | + } |
| 20 | + |
| 21 | + // 2. Calculate the total XOR sum of all node values |
| 22 | + totalXorSum := 0 |
| 23 | + for _, num := range nums { |
| 24 | + totalXorSum ^= num |
| 25 | + } |
| 26 | + |
| 27 | + // 3. Prepare slices for DFS pre-calculation |
| 28 | + // subtreeXor[i]: XOR sum of nodes in the subtree rooted at i (including i) |
| 29 | + subtreeXor := make([]int, n) |
| 30 | + // tin[i]: Entry time of node i in DFS traversal |
| 31 | + tin := make([]int, n) |
| 32 | + // tout[i]: Exit time of node i in DFS traversal (after visiting all its descendants) |
| 33 | + tout := make([]int, n) |
| 34 | + timer := 0 // Global timer for assigning tin/tout values |
| 35 | + |
| 36 | + // DFS function to compute subtreeXor, tin, and tout |
| 37 | + var dfs func(u, p int) // u: current node, p: parent node |
| 38 | + dfs = func(u, p int) { |
| 39 | + timer++ |
| 40 | + tin[u] = timer // Mark entry time for node u |
| 41 | + |
| 42 | + subtreeXor[u] = nums[u] // Initialize subtree XOR with current node's value |
| 43 | + |
| 44 | + // Traverse all neighbors of u |
| 45 | + for _, v := range adj[u] { |
| 46 | + if v == p { // Skip if v is the parent of u |
| 47 | + continue |
| 48 | + } |
| 49 | + dfs(v, u) // Recursively call DFS for child v |
| 50 | + subtreeXor[u] ^= subtreeXor[v] // Aggregate child's subtree XOR into current node's |
| 51 | + } |
| 52 | + |
| 53 | + timer++ |
| 54 | + tout[u] = timer // Mark exit time for node u |
| 55 | + } |
| 56 | + |
| 57 | + // Start DFS from node 0 (arbitrary root), with -1 as its virtual parent |
| 58 | + dfs(0, -1) |
| 59 | + |
| 60 | + // Initialize minimum score to a very large value |
| 61 | + minScore := math.MaxInt32 |
| 62 | + |
| 63 | + // 4. Enumerate all possible pairs of distinct nodes (i, j) |
| 64 | + // These nodes represent the "roots" of the two subtrees that will be cut off. |
| 65 | + // The edges being cut are implicitly (parent[i], i) and (parent[j], j). |
| 66 | + // We start from node 1 because node 0 is the root and does not have a "parent edge" to cut. |
| 67 | + for i := 1; i < n; i++ { |
| 68 | + for j := i + 1; j < n; j++ { // j must be different from i |
| 69 | + |
| 70 | + // Check if i is an ancestor of j using DFS timestamps |
| 71 | + // (tin[i] < tin[j] and tout[i] > tout[j]) |
| 72 | + isIAncestorOfJ := (tin[i] < tin[j] && tout[i] > tout[j]) |
| 73 | + // Check if j is an ancestor of i using DFS timestamps |
| 74 | + isJAncestorOfI := (tin[j] < tin[i] && tout[j] > tout[i]) |
| 75 | + |
| 76 | + var xorVal1, xorVal2, xorVal3 int // The three component XOR sums |
| 77 | + |
| 78 | + if isIAncestorOfJ { |
| 79 | + // Case 1: Node i is an ancestor of node j. |
| 80 | + // This means j's subtree is entirely contained within i's subtree. |
| 81 | + // The three components are: |
| 82 | + // - Component A: The subtree rooted at j. (xorVal1) |
| 83 | + // - Component B: The part of i's subtree *outside* j's subtree. (xorVal2) |
| 84 | + // - Component C: The rest of the tree (outside i's subtree). (xorVal3) |
| 85 | + xorVal1 = subtreeXor[j] |
| 86 | + xorVal2 = subtreeXor[i] ^ subtreeXor[j] // XOR sum of i's subtree excluding j's subtree |
| 87 | + xorVal3 = totalXorSum ^ subtreeXor[i] // Total XOR sum excluding i's subtree |
| 88 | + } else if isJAncestorOfI { |
| 89 | + // Case 2: Node j is an ancestor of node i. |
| 90 | + // This is symmetric to Case 1. Swap roles of i and j for calculation. |
| 91 | + xorVal1 = subtreeXor[i] |
| 92 | + xorVal2 = subtreeXor[j] ^ subtreeXor[i] // XOR sum of j's subtree excluding i's subtree |
| 93 | + xorVal3 = totalXorSum ^ subtreeXor[j] // Total XOR sum excluding j's subtree |
| 94 | + } else { |
| 95 | + // Case 3: Nodes i and j are not ancestors of each other. |
| 96 | + // Their respective subtrees are disjoint. |
| 97 | + // The three components are: |
| 98 | + // - Component A: The subtree rooted at i. (xorVal1) |
| 99 | + // - Component B: The subtree rooted at j. (xorVal2) |
| 100 | + // - Component C: The rest of the tree (outside both i's and j's subtrees). (xorVal3) |
| 101 | + xorVal1 = subtreeXor[i] |
| 102 | + xorVal2 = subtreeXor[j] |
| 103 | + xorVal3 = totalXorSum ^ subtreeXor[i] ^ subtreeXor[j] // Total XOR sum excluding both i's and j's subtrees |
| 104 | + } |
| 105 | + |
| 106 | + // Store the three XOR values in a slice, sort them, and calculate the difference. |
| 107 | + currentXors := []int{xorVal1, xorVal2, xorVal3} |
| 108 | + sort.Ints(currentXors) // Sort to easily find min and max |
| 109 | + |
| 110 | + // Calculate the score for this pair of edge removals |
| 111 | + diff := currentXors[2] - currentXors[0] // Largest XOR - Smallest XOR |
| 112 | + |
| 113 | + // Update the minimum score found so far |
| 114 | + if diff < minScore { |
| 115 | + minScore = diff |
| 116 | + } |
| 117 | + } |
| 118 | + } |
| 119 | + |
| 120 | + return minScore |
5 | 121 | }
|
0 commit comments