#include <bits/stdc++.h>
using namespace std;
int n, m, ans[1000005], Ans;
unordered_map<int, int> mp[1000005];
int get(int i, int j) {
  if (mp[i].find(j) != mp[i].end()) return mp[i][j];
  printf("? %d %d\n", i, j);
  fflush(stdout);
  int res;
  scanf("%d", &res);
  mp[i][j] = res;
  return res;
}
struct node {
  int val;
  char opt;
  node *lst, *nxt;
  node() {
    val = opt = 0;
    lst = nxt = NULL;
  }
};
struct List {
  int len;
  node *s, *e;
  List() {
    len = 0;
    s = new node();
    s->opt = 1;
    e = new node();
    e->opt = -1;
    s->nxt = e;
    e->lst = s;
  }
  void append(int x) {
    node *n = new node();
    n->val = x;
    node *a = e->lst;
    a->nxt = n;
    n->lst = a;
    n->nxt = e;
    e->lst = n;
    ++len;
  }
  List(const List &a) {
    len = 0;
    s = new node();
    s->opt = 1;
    e = new node();
    e->opt = -1;
    s->nxt = e;
    e->lst = s;
    node *n = a.s->nxt;
    while (n->opt != -1) append(n->val), n = n->nxt;
  }
  node *del(node *n) {
    --len;
    node *a = n->lst, *b = n->nxt;
    a->nxt = b;
    b->lst = a;
    delete (n);
    return a;
  }
};
struct submat {
  List r, c;
} A;
submat reduce(const submat &A) {
  submat B;
  B.r = List(A.r);
  B.c = List(A.c);
  int n = A.r.len, m = A.c.len;
  if (n >= m) return B;
  node *nr = B.r.s->nxt, *nc = B.c.s->nxt;
  int k = 1;
  while (n < m) {
    if (get(nr->val, nc->val) >= get(nr->val, nc->nxt->val)) {
      nc = B.c.del(nc);
      --m;
      if (k > 1) {
        --k;
        nr = nr->lst;
      } else {
        nr = B.r.s->nxt, nc = B.c.s->nxt;
      }
    } else if (k == n) {
      B.c.del(nc->nxt);
      --m;
    } else {
      k = k + 1;
      nr = nr->nxt, nc = nc->nxt;
    }
  }
  return B;
}
void SMAWK(submat A) {
  int n = A.r.len, m = A.c.len;
  if (n == 1) {
    int x = A.r.s->nxt->val, minp = 0, minv = 0x3f3f3f3f;
    node *nc = A.c.s->nxt;
    while (nc->opt != -1) {
      if (get(x, nc->val) < minv) minp = nc->val, minv = get(x, nc->val);
      nc = nc->nxt;
    }
    ans[x] = minp;
    Ans = min(minv, Ans);
    return;
  }
  if (m == 1) {
    int y = A.c.s->nxt->val;
    node *nr = A.r.s->nxt;
    while (nr->opt != -1) {
      ans[nr->val] = y;
      nr = nr->nxt;
    }
    return;
  }
  submat B = reduce(A), C;
  C.c = List(B.c);
  node *nr = B.r.s->nxt;
  bool o = 0;
  while (nr->opt != -1) {
    if (o) C.r.append(nr->val);
    nr = nr->nxt;
    o ^= 1;
  }
  SMAWK(C);
  nr = B.r.s->nxt;
  o = 0;
  node *nc = B.c.s->nxt;
  while (nr->opt != -1) {
    if (!o) {
      int z = ans[nr->nxt->val], x = nr->val, minp = 0, minv = 0x3f3f3f3f;
      if (z == 0) z = 0x3f3f3f3f;
      while (nc->opt != -1 && nc->val <= z) {
        if (get(x, nc->val) < minv) minp = nc->val, minv = get(x, nc->val);
        nc = nc->nxt;
      }
      if (nc->lst->val == z) nc = nc->lst;
      ans[x] = minp;
      Ans = min(Ans, minv);
    }
    nr = nr->nxt;
    o ^= 1;
  }
}
int main() {
  Ans = 0x3f3f3f3f;
  scanf("%d%d", &n, &m);
  for (int i = 1; i <= n; ++i) A.r.append(i);
  for (int i = 1; i <= m; ++i) A.c.append(i);
  SMAWK(A);
  printf("! %d\n", Ans);
  return 0;
}
