```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)
}
}
```