```go
package main
import (
"bufio"
"fmt"
"os"
"strconv"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
scanner.Split(bufio.ScanWords)
writer := bufio.NewWriter(os.Stdout)
defer writer.Flush()
// Read number of queries
if !scanner.Scan() {
return
}
q, _ := strconv.Atoi(scanner.Text())
// Array to store position of each book ID.
// Max ID is 2*10^5.
pos := make([]int, 200005)
// Initialize pointers for the left and right ends of the shelf.
// Using l=1, r=0 ensures that the first insertion (whether L or R)
// sets the range to size 1 correctly.
// If L: l becomes 0. Range [0, 0].
// If R: r becomes 1. Range [1, 1].
l := 1
r := 0
for i := 0; i < q; i++ {
scanner.Scan()
op := scanner.Text()[0] // 'L', 'R', or '?'
scanner.Scan()
id, _ := strconv.Atoi(scanner.Text())
if op == 'L' {
l--
pos[id] = l
} else if op == 'R' {
r++
pos[id] = r
} else {
// Query '?'
// Calculate books to remove from left vs right
fromLeft := pos[id] - l
fromRight := r - pos[id]
if fromLeft < fromRight {
fmt.Fprintln(writer, fromLeft)
} else {
fmt.Fprintln(writer, fromRight)
}
}
}
}
```