```go
package main
import (
"bufio"
"fmt"
"os"
)
type TrieNode struct {
child [2]int32
count int32
}
const MAXN = 200005
var (
D = make([]int, MAXN)
depth = make([]int8, MAXN)
head = make([]int, MAXN)
to = make([]int, MAXN*2)
weight = make([]int, MAXN*2)
nxt = make([]int, MAXN*2)
trie = make([]TrieNode, 6500000)
allocIdx int32
root0 int32
root1 int32
)
func newNode() int32 {
allocIdx++
if int(allocIdx) >= len(trie) {
trie = append(trie, TrieNode{})
} else {
trie[allocIdx] = TrieNode{}
}
return allocIdx
}
func insert(root int32, val int) {
curr := root
trie[curr].count++
for i := 29; i >= 0; i-- {
bit := (val >> i) & 1
if trie[curr].child[bit] == 0 {
trie[curr].child[bit] = newNode()
}
curr = trie[curr].child[bit]
trie[curr].count++
}
}
func remove(root int32, val int) {
curr := root
trie[curr].count--
for i := 29; i >= 0; i-- {
bit := (val >> i) & 1
curr = trie[curr].child[bit]
trie[curr].count--
}
}
func maxXor(root int32, val int) int {
if trie[root].count == 0 {
return -1
}
curr := root
ans := 0
for i := 29; i >= 0; i-- {
bit := (val >> i) & 1
alt := 1 - bit
if trie[curr].child[alt] != 0 && trie[trie[curr].child[alt]].count > 0 {
ans |= (1 << i)
curr = trie[curr].child[alt]
} else {
curr = trie[curr].child[bit]
}
}
return ans
}
func dfs(u, p, d, xorSum int) {
depth[u] = int8(d & 1)
D[u] = xorSum
if depth[u] == 0 {
insert(root0, xorSum)
} else {
insert(root1, xorSum)
}
for e := head[u]; e != 0; e = nxt[e] {
v := to[e]
if v != p {
dfs(v, u, d+1, xorSum^weight[e])
}
}
}
func main() {
scanner := bufio.NewScanner(os.Stdin)
scanner.Split(bufio.ScanWords)
buffer := make([]byte, 1024*1024)
scanner.Buffer(buffer, 1024*1024*10)
readInt := func() int {
scanner.Scan()
s := scanner.Bytes()
v := 0
for _, b := range s {
v = v*10 + int(b-'0')
}
return v
}
readOp := func() byte {
scanner.Scan()
return scanner.Bytes()[0]
}
if !scanner.Scan() {
return
}
s := scanner.Bytes()
t := 0
for _, b := range s {
t = t*10 + int(b-'0')
}
writer := bufio.NewWriter(os.Stdout)
defer writer.Flush()
for tc := 0; tc < t; tc++ {
n := readInt()
m := readInt()
for i := 1; i <= n; i++ {
head[i] = 0
}
edgeCnt := 0
addEdge := func(u, v, w int) {
edgeCnt++
to[edgeCnt] = v
weight[edgeCnt] = w
nxt[edgeCnt] = head[u]
head[u] = edgeCnt
}
for i := 0; i < n-1; i++ {
u := readInt()
v := readInt()
w := readInt()
addEdge(u, v, w)
addEdge(v, u, w)
}
allocIdx = 0
trie[0] = TrieNode{}
root0 = newNode()
root1 = newNode()
dfs(1, 0, 0, 0)
lazy := 0
for i := 0; i < m; i++ {
op := readOp()
if op == '^' {
y := readInt()
lazy ^= y
} else {
v := readInt()
x := readInt()
var currDv int
if depth[v] == 0 {
currDv = D[v]
} else {
currDv = D[v] ^ lazy
}
if depth[v] == 0 {
remove(root0, D[v])
} else {
remove(root1, D[v])
}
q0 := currDv ^ x
q1 := currDv ^ x ^ lazy
ans := -1
if res := maxXor(root0, q0); res != -1 {
if res > ans {
ans = res
}
}
if res := maxXor(root1, q1); res != -1 {
if res > ans {
ans = res
}
}
fmt.Fprint(writer, ans, " ")
if depth[v] == 0 {
insert(root0, D[v])
} else {
insert(root1, D[v])
}
}
}
fmt.Fprintln(writer)
}
}
```