```go
package main
import (
"bufio"
"fmt"
"os"
)
var (
reader *bufio.Reader
writer *bufio.Writer
minVal int
)
func query(r, c int) int {
fmt.Fprintf(writer, "? %d %d\n", r+1, c+1)
writer.Flush()
var h int
fmt.Fscan(reader, &h)
if h < minVal {
minVal = h
}
return h
}
func smawk(rows, cols []int) []int {
if len(rows) == 0 {
return []int{}
}
// Reduce columns
stack := make([]int, 0, len(rows))
for _, c := range cols {
for len(stack) > 0 {
rowIdx := len(stack) - 1
r := rows[rowIdx]
cTop := stack[len(stack)-1]
vTop := query(r, cTop)
vCur := query(r, c)
if vCur < vTop {
stack = stack[:len(stack)-1]
} else {
break
}
}
if len(stack) < len(rows) {
stack = append(stack, c)
}
}
reduceCols := stack
// Solve for odd rows recursively
oddRows := make([]int, 0, len(rows)/2)
for i := 1; i < len(rows); i += 2 {
oddRows = append(oddRows, rows[i])
}
var oddResults []int
if len(oddRows) > 0 {
oddResults = smawk(oddRows, reduceCols)
}
result := make([]int, len(rows))
for i, val := range oddResults {
result[2*i+1] = val
}
// Fill even rows
j := 0
for i := 0; i < len(rows); i += 2 {
var limit int
if i+1 < len(rows) {
limit = result[i+1]
} else {
limit = reduceCols[len(reduceCols)-1]
}
bestVal := int(^uint(0) >> 1)
bestCol := -1
k := j
for k < len(reduceCols) {
col := reduceCols[k]
val := query(rows[i], col)
if val < bestVal {
bestVal = val
bestCol = col
}
if col == limit {
break
}
k++
}
result[i] = bestCol
j = k
}
return result
}
func main() {
reader = bufio.NewReader(os.Stdin)
writer = bufio.NewWriter(os.Stdout)
var n, m int
fmt.Fscan(reader, &n, &m)
rows := make([]int, n)
for i := 0; i < n; i++ {
rows[i] = i
}
cols := make([]int, m)
for i := 0; i < m; i++ {
cols[i] = i
}
minVal = int(^uint(0) >> 1)
smawk(rows, cols)
fmt.Fprintf(writer, "! %d\n", minVal)
writer.Flush()
}
```