← Home
```go
package main

import (
	"bufio"
	"os"
)

var (
	reader *bufio.Reader
	writer *bufio.Writer
	adj    [][]int
	tin    []int
	tout   []int
	timer  int
	tree1  []int
	tree2  []int
)

func readInt() int {
	var x int
	var c byte
	var err error
	for {
		c, err = reader.ReadByte()
		if err != nil {
			return x
		}
		if c >= '0' && c <= '9' {
			x = int(c - '0')
			break
		}
	}
	for {
		c, err = reader.ReadByte()
		if err != nil {
			break
		}
		if c >= '0' && c <= '9' {
			x = x*10 + int(c-'0')
		} else {
			break
		}
	}
	return x
}

func dfs(u, p int) {
	timer++
	tin[u] = timer
	for _, v := range adj[u] {
		if v != p {
			dfs(v, u)
		}
	}
	tout[u] = timer
}

// SegTree1: Range Set (Max), Point Query
// tree1[v] stores the timestamp of the latest Type 1 operation covering the range of node v.
// Since timestamps are increasing, we just keep the maximum.
// A point query at pos returns the max timestamp along the path from root to leaf.
func update1(v, tl, tr, l, r, val int) {
	if l > r {
		return
	}
	if l == tl && r == tr {
		if val > tree1[v] {
			tree1[v] = val
		}
		return
	}
	tm := (tl + tr) >> 1
	update1(2*v, tl, tm, l, min(r, tm), val)
	update1(2*v+1, tm+1, tr, max(l, tm+1), r, val)
}

func query1(v, tl, tr, pos int) int {
	res := tree1[v]
	if tl == tr {
		return res
	}
	tm := (tl + tr) >> 1
	var val int
	if pos <= tm {
		val = query1(2*v, tl, tm, pos)
	} else {
		val = query1(2*v+1, tm+1, tr, pos)
	}
	if val > res {
		return val
	}
	return res
}

// SegTree2: Point Update, Range Max
// tree2[v] stores the max timestamp of Type 2 operations in the subtree (range).
func update2(v, tl, tr, pos, val int) {
	if tl == tr {
		tree2[v] = val
		return
	}
	tm := (tl + tr) >> 1
	if pos <= tm {
		update2(2*v, tl, tm, pos, val)
	} else {
		update2(2*v+1, tm+1, tr, pos, val)
	}
	if tree2[2*v] > tree2[2*v+1] {
		tree2[v] = tree2[2*v]
	} else {
		tree2[v] = tree2[2*v+1]
	}
}

func query2(v, tl, tr, l, r int) int {
	if l > r {
		return 0
	}
	if l == tl && r == tr {
		return tree2[v]
	}
	tm := (tl + tr) >> 1
	v1 := query2(2*v, tl, tm, l, min(r, tm))
	v2 := query2(2*v+1, tm+1, tr, max(l, tm+1), r)
	if v1 > v2 {
		return v1
	}
	return v2
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func main() {
	reader = bufio.NewReaderSize(os.Stdin, 1<<20)
	writer = bufio.NewWriterSize(os.Stdout, 1<<20)
	defer writer.Flush()

	n := readInt()
	adj = make([][]int, n+1)
	for i := 0; i < n-1; i++ {
		u := readInt()
		v := readInt()
		adj[u] = append(adj[u], v)
		adj[v] = append(adj[v], u)
	}

	tin = make([]int, n+1)
	tout = make([]int, n+1)
	dfs(1, 0)

	tree1 = make([]int, 4*n+1)
	tree2 = make([]int, 4*n+1)

	q := readInt()
	for i := 1; i <= q; i++ {
		t := readInt()
		v := readInt()
		if t == 1 {
			// Fill v: updates subtree of v
			update1(1, 1, n, tin[v], tout[v], i)
		} else if t == 2 {
			// Empty v: updates point v (affecting queries on ancestors)
			update2(1, 1, n, tin[v], i)
		} else {
			// Query v
			// v is full if the last fill on any ancestor was later than
			// the last empty on any descendant.
			lastFill := query1(1, 1, n, tin[v])
			lastEmpty := query2(1, 1, n, tin[v], tout[v])
			if lastFill > lastEmpty {
				writer.WriteString("1\n")
			} else {
				writer.WriteString("0\n")
			}
		}
	}
}
```