Skip to content

Add solution and test-cases for problem 2322 #1269

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -1,28 +1,48 @@
# [2322.Minimum Score After Removals on a Tree][title]

> [!WARNING|style:flat]
> This question is temporarily unanswered if you have good ideas. Welcome to [Create Pull Request PR](https://github.com/kylesliu/awesome-golang-algorithm)

## Description
There is an undirected connected tree with n nodes labeled from `0` to `n - 1` and `n - 1` edges.

You are given a **0-indexed** integer array `nums` of length `n` where `nums[i]` represents the value of the `ith` node. You are also given a 2D integer array `edges` of length `n - 1` where `edges[i] = [ai, bi]` indicates that there is an edge between nodes `ai` and `bi` in the tree.

Remove two **distinct** edges of the tree to form three connected components. For a pair of removed edges, the following steps are defined:

1. Get the XOR of all the values of the nodes for **each** of the three components respectively.
2. The **difference** between the **largest** XOR value and the **smallest** XOR value is the **score** of the pair.

- For example, say the three components have the node values: `[4,5,7], [1,9], and [3,3,3]`. The three XOR values are `4 ^ 5 ^ 7 = 6`, `1 ^ 9 = 8`, and `3 ^ 3 ^ 3 = 3`. The largest XOR value is `8` and the smallest XOR value is `3`. The score is then `8 - 3 = 5`.

**Example 1:**
Return the **minimum** score of any possible pair of edge removals on the given tree.

**Example 1:**

![1](./1.png)

```
Input: a = "11", b = "1"
Output: "100"
Input: nums = [1,5,5,4,11], edges = [[0,1],[1,2],[1,3],[3,4]]
Output: 9
Explanation: The diagram above shows a way to make a pair of removals.
- The 1st component has nodes [1,3,4] with values [5,4,11]. Its XOR value is 5 ^ 4 ^ 11 = 10.
- The 2nd component has node [0] with value [1]. Its XOR value is 1 = 1.
- The 3rd component has node [2] with value [5]. Its XOR value is 5 = 5.
The score is the difference between the largest and smallest XOR value which is 10 - 1 = 9.
It can be shown that no other pair of removals will obtain a smaller score than 9.
```

## 题意
> ...
**Example 2:**

## 题解
![2](./2.png)

### 思路1
> ...
Minimum Score After Removals on a Tree
```go
```

Input: nums = [5,5,2,4,4,2], edges = [[0,1],[1,2],[5,2],[4,3],[1,3]]
Output: 0
Explanation: The diagram above shows a way to make a pair of removals.
- The 1st component has nodes [3,4] with values [4,4]. Its XOR value is 4 ^ 4 = 0.
- The 2nd component has nodes [1,0] with values [5,5]. Its XOR value is 5 ^ 5 = 0.
- The 3rd component has nodes [2,5] with values [2,2]. Its XOR value is 2 ^ 2 = 0.
The score is the difference between the largest and smallest XOR value which is 0 - 0 = 0.
We cannot obtain a smaller score than 0.
```

## 结语

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,121 @@
package Solution

func Solution(x bool) bool {
return x
import (
"math"
"sort"
)

// minimumScore calculates the minimum score achievable by removing two distinct edges from a tree.
// The score is defined as the difference between the largest and smallest XOR values of the three resulting components.
func Solution(nums []int, edges [][]int) int {
n := len(nums) // Number of nodes

// 1. Build adjacency list for graph traversal
adj := make([][]int, n)
for _, edge := range edges {
u, v := edge[0], edge[1]
adj[u] = append(adj[u], v)
adj[v] = append(adj[v], u) // Undirected graph
}

// 2. Calculate the total XOR sum of all node values
totalXorSum := 0
for _, num := range nums {
totalXorSum ^= num
}

// 3. Prepare slices for DFS pre-calculation
// subtreeXor[i]: XOR sum of nodes in the subtree rooted at i (including i)
subtreeXor := make([]int, n)
// tin[i]: Entry time of node i in DFS traversal
tin := make([]int, n)
// tout[i]: Exit time of node i in DFS traversal (after visiting all its descendants)
tout := make([]int, n)
timer := 0 // Global timer for assigning tin/tout values

// DFS function to compute subtreeXor, tin, and tout
var dfs func(u, p int) // u: current node, p: parent node
dfs = func(u, p int) {
timer++
tin[u] = timer // Mark entry time for node u

subtreeXor[u] = nums[u] // Initialize subtree XOR with current node's value

// Traverse all neighbors of u
for _, v := range adj[u] {
if v == p { // Skip if v is the parent of u
continue
}
dfs(v, u) // Recursively call DFS for child v
subtreeXor[u] ^= subtreeXor[v] // Aggregate child's subtree XOR into current node's
}

timer++
tout[u] = timer // Mark exit time for node u
}

// Start DFS from node 0 (arbitrary root), with -1 as its virtual parent
dfs(0, -1)

// Initialize minimum score to a very large value
minScore := math.MaxInt32

// 4. Enumerate all possible pairs of distinct nodes (i, j)
// These nodes represent the "roots" of the two subtrees that will be cut off.
// The edges being cut are implicitly (parent[i], i) and (parent[j], j).
// We start from node 1 because node 0 is the root and does not have a "parent edge" to cut.
for i := 1; i < n; i++ {
for j := i + 1; j < n; j++ { // j must be different from i

// Check if i is an ancestor of j using DFS timestamps
// (tin[i] < tin[j] and tout[i] > tout[j])
isIAncestorOfJ := (tin[i] < tin[j] && tout[i] > tout[j])
// Check if j is an ancestor of i using DFS timestamps
isJAncestorOfI := (tin[j] < tin[i] && tout[j] > tout[i])

var xorVal1, xorVal2, xorVal3 int // The three component XOR sums

if isIAncestorOfJ {
// Case 1: Node i is an ancestor of node j.
// This means j's subtree is entirely contained within i's subtree.
// The three components are:
// - Component A: The subtree rooted at j. (xorVal1)
// - Component B: The part of i's subtree *outside* j's subtree. (xorVal2)
// - Component C: The rest of the tree (outside i's subtree). (xorVal3)
xorVal1 = subtreeXor[j]
xorVal2 = subtreeXor[i] ^ subtreeXor[j] // XOR sum of i's subtree excluding j's subtree
xorVal3 = totalXorSum ^ subtreeXor[i] // Total XOR sum excluding i's subtree
} else if isJAncestorOfI {
// Case 2: Node j is an ancestor of node i.
// This is symmetric to Case 1. Swap roles of i and j for calculation.
xorVal1 = subtreeXor[i]
xorVal2 = subtreeXor[j] ^ subtreeXor[i] // XOR sum of j's subtree excluding i's subtree
xorVal3 = totalXorSum ^ subtreeXor[j] // Total XOR sum excluding j's subtree
} else {
// Case 3: Nodes i and j are not ancestors of each other.
// Their respective subtrees are disjoint.
// The three components are:
// - Component A: The subtree rooted at i. (xorVal1)
// - Component B: The subtree rooted at j. (xorVal2)
// - Component C: The rest of the tree (outside both i's and j's subtrees). (xorVal3)
xorVal1 = subtreeXor[i]
xorVal2 = subtreeXor[j]
xorVal3 = totalXorSum ^ subtreeXor[i] ^ subtreeXor[j] // Total XOR sum excluding both i's and j's subtrees
}

// Store the three XOR values in a slice, sort them, and calculate the difference.
currentXors := []int{xorVal1, xorVal2, xorVal3}
sort.Ints(currentXors) // Sort to easily find min and max

// Calculate the score for this pair of edge removals
diff := currentXors[2] - currentXors[0] // Largest XOR - Smallest XOR

// Update the minimum score found so far
if diff < minScore {
minScore = diff
}
}
}

return minScore
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,34 @@ func TestSolution(t *testing.T) {
// 测试用例
cases := []struct {
name string
inputs bool
expect bool
nums []int
edges [][]int
expect int
}{
{"TestCase", true, true},
{"TestCase", true, true},
{"TestCase", false, false},
{"TestCase1", []int{1, 5, 5, 4, 11}, [][]int{
{0, 1}, {1, 2}, {1, 3}, {3, 4},
}, 9},
{"TestCase2", []int{5, 5, 2, 4, 4, 2}, [][]int{
{0, 1}, {1, 2}, {5, 2}, {4, 3}, {1, 3},
}, 0},
}

// 开始测试
for i, c := range cases {
t.Run(c.name+" "+strconv.Itoa(i), func(t *testing.T) {
got := Solution(c.inputs)
got := Solution(c.nums, c.edges)
if !reflect.DeepEqual(got, c.expect) {
t.Fatalf("expected: %v, but got: %v, with inputs: %v",
c.expect, got, c.inputs)
t.Fatalf("expected: %v, but got: %v, with inputs: %v %v",
c.expect, got, c.nums, c.edges)
}
})
}
}

// 压力测试
// 压力测试
func BenchmarkSolution(b *testing.B) {
}

// 使用案列
// 使用案列
func ExampleSolution() {
}
Loading