← Home
```go
package main

import (
	"bufio"
	"fmt"
	"math/bits"
	"os"
	"sort"
	"strconv"
)

type Ray struct {
	x, y int64
}

func abs(x int64) int64 {
	if x < 0 {
		return -x
	}
	return x
}

func gcd(a, b int64) int64 {
	for b != 0 {
		a, b = b, a%b
	}
	return a
}

func half(A Ray) int {
	if A.y > 0 || (A.y == 0 && A.x > 0) {
		return 1
	}
	return 2
}

func cross(A, B Ray) int {
	hi1, lo1 := bits.Mul64(uint64(abs(A.x)), uint64(abs(B.y)))
	hi2, lo2 := bits.Mul64(uint64(abs(A.y)), uint64(abs(B.x)))

	sign1 := 1
	if (A.x < 0) != (B.y < 0) {
		sign1 = -1
	}
	if A.x == 0 || B.y == 0 {
		sign1 = 0
	}

	sign2 := 1
	if (A.y < 0) != (B.x < 0) {
		sign2 = -1
	}
	if A.y == 0 || B.x == 0 {
		sign2 = 0
	}

	if sign1 != sign2 {
		if sign1 > sign2 {
			return 1
		}
		return -1
	}
	if sign1 == 0 {
		return 0
	}
	if sign1 > 0 {
		if hi1 != hi2 {
			if hi1 > hi2 {
				return 1
			}
			return -1
		}
		if lo1 != lo2 {
			if lo1 > lo2 {
				return 1
			}
			return -1
		}
		return 0
	}
	if hi1 != hi2 {
		if hi1 > hi2 {
			return -1
		}
		return 1
	}
	if lo1 != lo2 {
		if lo1 > lo2 {
			return -1
		}
		return 1
	}
	return 0
}

func isBefore(A, B Ray) bool {
	h1, h2 := half(A), half(B)
	if h1 != h2 {
		return h1 < h2
	}
	return cross(A, B) > 0
}

type SegTree struct {
	sum []int
	n   int
}

func NewSegTree(M int) *SegTree {
	n := 1
	for n < M {
		n *= 2
	}
	return &SegTree{
		sum: make([]int, 2*n),
		n:   n,
	}
}

func (st *SegTree) Update(idx, val int) {
	idx += st.n
	st.sum[idx] += val
	for idx > 1 {
		idx /= 2
		st.sum[idx] = st.sum[idx*2] + st.sum[idx*2+1]
	}
}

func (st *SegTree) queryMaxRight(node, l, r, ql, qr int) int {
	if ql > r || qr < l || st.sum[node] == 0 {
		return -1
	}
	if l == r {
		return l
	}
	mid := (l + r) / 2
	res := st.queryMaxRight(node*2+1, mid+1, r, ql, qr)
	if res != -1 {
		return res
	}
	return st.queryMaxRight(node*2, l, mid, ql, qr)
}

func (st *SegTree) queryMinLeft(node, l, r, ql, qr int) int {
	if ql > r || qr < l || st.sum[node] == 0 {
		return -1
	}
	if l == r {
		return l
	}
	mid := (l + r) / 2
	res := st.queryMinLeft(node*2, l, mid, ql, qr)
	if res != -1 {
		return res
	}
	return st.queryMinLeft(node*2+1, mid+1, r, ql, qr)
}

func (st *SegTree) FindPrev(x int) int {
	if st.sum[1] == 0 {
		return -1
	}
	if x > 0 {
		y := st.queryMaxRight(1, 0, st.n-1, 0, x-1)
		if y != -1 {
			return y
		}
	}
	return st.queryMaxRight(1, 0, st.n-1, 0, st.n-1)
}

func (st *SegTree) FindNext(x int) int {
	if st.sum[1] == 0 {
		return -1
	}
	if x < st.n-1 {
		y := st.queryMinLeft(1, 0, st.n-1, x+1, st.n-1)
		if y != -1 {
			return y
		}
	}
	return st.queryMinLeft(1, 0, st.n-1, 0, st.n-1)
}

type Query struct {
	op      byte
	id      int
	S, P, G int64
}

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	scanner.Split(bufio.ScanWords)
	buf := make([]byte, 1024*1024)
	scanner.Buffer(buf, 10*1024*1024)

	nextString := func() string {
		scanner.Scan()
		return scanner.Text()
	}

	nextInt := func() int {
		s := nextString()
		i, _ := strconv.Atoi(s)
		return i
	}

	nextInt64 := func() int64 {
		s := nextString()
		i, _ := strconv.ParseInt(s, 10, 64)
		return i
	}

	if !scanner.Scan() {
		return
	}
	Sf, _ := strconv.ParseInt(scanner.Text(), 10, 64)
	Pf := nextInt64()
	Gf := nextInt64()

	var u1, u2, u3 int64
	var v1, v2, v3 int64

	if Sf > 0 {
		u1, u2, u3 = -Pf, Sf, 0
		v1, v2, v3 = -Gf, 0, Sf
	} else if Pf > 0 {
		u1, u2, u3 = 0, -Gf, Pf
		v1, v2, v3 = 1, 0, 0
	} else {
		u1, u2, u3 = 1, 0, 0
		v1, v2, v3 = 0, 1, 0
	}

	N := nextInt()
	queries := make([]Query, N)
	var rawRays []Ray

	bottlesZero := make([]bool, 0)
	bottleRayID := make([]int, 0)
	bottlesZero = append(bottlesZero, false)
	bottleRayID = append(bottleRayID, -1)

	for i := 0; i < N; i++ {
		opStr := nextString()
		op := opStr[0]
		queries[i].op = op
		if op == 'A' {
			S := nextInt64()
			P := nextInt64()
			G := nextInt64()
			queries[i].S = S
			queries[i].P = P
			queries[i].G = G

			X := S*u1 + P*u2 + G*u3
			Y := S*v1 + P*v2 + G*v3
			if X == 0 && Y == 0 {
				bottlesZero = append(bottlesZero, true)
				bottleRayID = append(bottleRayID, -1)
			} else {
				g := gcd(abs(X), abs(Y))
				r := Ray{X / g, Y / g}
				bottlesZero = append(bottlesZero, false)
				bottleRayID = append(bottleRayID, len(rawRays))
				rawRays = append(rawRays, r)
			}
		} else {
			id := nextInt()
			queries[i].id = id
		}
	}

	sort.Slice(rawRays, func(i, j int) bool {
		return isBefore(rawRays[i], rawRays[j])
	})

	var distinctRays []Ray
	if len(rawRays) > 0 {
		distinctRays = append(distinctRays, rawRays[0])
		for i := 1; i < len(rawRays); i++ {
			if isBefore(rawRays[i-1], rawRays[i]) {
				distinctRays = append(distinctRays, rawRays[i])
			}
		}
	}

	M := len(distinctRays)
	var R []int
	var opp []int
	var st *SegTree

	if M > 0 {
		R = make([]int, M)
		for i := 0; i < M; i++ {
			low := i
			high := i + M - 1
			ans := i
			for low <= high {
				mid := (low + high) / 2
				A := distinctRays[i]
				B := distinctRays[mid%M]
				if mid == i {
					ans = mid
					low = mid + 1
					continue
				}
				if cross(A, B) > 0 {
					ans = mid
					low = mid + 1
				} else {
					high = mid - 1
				}
			}
			R[i] = ans
		}

		opp = make([]int, M)
		for i := 0; i < M; i++ {
			target := Ray{-distinctRays[i].x, -distinctRays[i].y}
			idx := sort.Search(M, func(j int) bool {
				return !isBefore(distinctRays[j], target)
			})
			if idx < M && distinctRays[idx] == target {
				opp[i] = idx
			} else {
				opp[i] = -1
			}
		}

		st = NewSegTree(M)
	}

	getRayID := func(r Ray) int {
		return sort.Search(M, func(j int) bool {
			return !isBefore(distinctRays[j], r)
		})
	}

	for i := 1; i < len(bottleRayID); i++ {
		if !bottlesZero[i] {
			bottleRayID[i] = getRayID(rawRays[bottleRayID[i]])
		}
	}

	isGapBad := func(A, B int) bool {
		if A == B {
			return true
		}
		next := B
		if B < A {
			next = B + M
		}
		return next > R[A]
	}

	C_0 := 0
	C_opp := 0
	badGaps := 0
	var count []int
	if M > 0 {
		count = make([]int, M)
	}

	out := bufio.NewWriter(os.Stdout)
	defer out.Flush()

	bottleIdx := 1
	for _, q := range queries {
		if q.op == 'A' {
			isZero := bottlesZero[bottleIdx]
			if isZero {
				C_0++
			} else {
				x := bottleRayID[bottleIdx]
				if count[x] == 0 {
					if st.sum[1] == 0 {
						if isGapBad(x, x) {
							badGaps++
						}
					} else {
						L := st.FindPrev(x)
						nxt := st.FindNext(x)
						if isGapBad(L, nxt) {
							badGaps--
						}
						if isGapBad(L, x) {
							badGaps++
						}
						if isGapBad(x, nxt) {
							badGaps++
						}
					}
					st.Update(x, 1)
					if opp[x] != -1 && count[opp[x]] > 0 {
						C_opp++
					}
				}
				count[x]++
			}
			bottleIdx++
		} else {
			targetIdx := q.id
			isZero := bottlesZero[targetIdx]
			if isZero {
				C_0--
			} else {
				x := bottleRayID[targetIdx]
				count[x]--
				if count[x] == 0 {
					if st.sum[1] == 1 {
						if isGapBad(x, x) {
							badGaps--
						}
					} else {
						L := st.FindPrev(x)
						nxt := st.FindNext(x)
						if isGapBad(L, x) {
							badGaps--
						}
						if isGapBad(x, nxt) {
							badGaps--
						}
						if isGapBad(L, nxt) {
							badGaps++
						}
					}
					st.Update(x, -1)
					if opp[x] != -1 && count[opp[x]] > 0 {
						C_opp--
					}
				}
			}
		}

		ans := 0
		if C_0 > 0 {
			ans = 1
		} else if C_opp > 0 {
			ans = 2
		} else if M > 0 && st.sum[1] >= 3 && badGaps == 0 {
			ans = 3
		}
		fmt.Fprintln(out, ans)
	}
}
```