#include <bits/stdc++.h>
#pragma warning(disable : 4996)
template <typename T>
T min(T x, T y) {
  return x < y ? x : y;
}
template <typename T>
T max(T x, T y) {
  return x > y ? x : y;
};
const long long INF = 2000000005;
const long long mod = 998244353;
const long long MAXN = 1000005;
const int T[11][11] = {
    {},
    {0, 15, 20, 20, 20, 20, 20, 20, 20, 20, 20},
    {0, 15, 20, 20, 20, 20, 20, 20, 20, 20, 20},
    {0, 15, 20, 20, 20, 20, 20, 20, 20, 20, 20},
    {0, 15, 20, 20, 20, 20, 20, 20, 20, 20, 20},
    {0, 15, 20, 20, 20, 20, 20, 20, 20, 20, 20},
    {0, 15, 20, 20, 20, 20, 20, 20, 20, 20, 20},
    {0, 15, 20, 20, 20, 20, 20, 20, 20, 20, 20},
    {0, 15, 20, 20, 20, 20, 20, 20, 20, 20, 20},
    {0, 15, 20, 20, 20, 20, 20, 20, 20, 20, 20},
    {0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 1},
};
int N, M;
std::unordered_map<int, int> MAP[MAXN];
int query(int x, int y) {
  if (MAP[x][y]) return MAP[x][y];
  int t;
  printf("? %d %d\n", x, y);
  fflush(stdout);
  scanf("%d", &t);
  return MAP[x][y] = t;
}
std::vector<int> solve(int n, int m, std::vector<int> x, std::vector<int> y) {
  std::vector<int> ans;
  if (n == 1) {
    int t = 0;
    for (int i = 0; i < m; i++)
      if (query(x[0], y[i]) < query(x[0], y[t])) t = i;
    ans.push_back(t);
    return ans;
  }
  if (m > n) {
    std::vector<int> S;
    S.push_back(0);
    for (int i = 1; i < m; i++) {
      while (S.size() && query(x[S.size() - 1], y[*S.rbegin()]) >
                             query(x[S.size() - 1], y[i]))
        S.pop_back();
      if (S.size() < n) S.push_back(i);
    }
    for (int i = 0; i < S.size(); i++) S[i] = y[S[i]];
    std::vector<int> tmp = solve(n, S.size(), x, S);
    int p = 0;
    for (int i = 0; i < n; i++) {
      while (y[p] != S[tmp[i]]) p++;
      tmp[i] = p;
    }
    return tmp;
  }
  std::vector<int> tx;
  for (int i = 0; 2 * i + 1 < n; i++) tx.push_back(x[2 * i + 1]);
  std::vector<int> tmp0, tmp1 = solve(n / 2, m, tx, y);
  for (int i = 0; 2 * i < n; i++) {
    int l = i ? tmp1[i - 1] : 0;
    int r = i < n / 2 ? tmp1[i] : m - 1;
    int t = l;
    for (int j = l; j <= r; j++)
      if (query(x[i * 2], y[j]) < query(x[i * 2], y[t])) t = j;
    tmp0.push_back(t);
  }
  for (int i = 0; i < n; i++) ans.push_back(i & 1 ? tmp1[i / 2] : tmp0[i / 2]);
  return ans;
}
int main() {
  std::vector<int> x, y;
  scanf("%d %d", &N, &M);
  for (int i = 1; i <= N; i++) x.push_back(i);
  for (int i = 1; i <= M; i++) y.push_back(i);
  std::vector<int> t = solve(N, M, x, y);
  for (int i = 0; i < N; i++) t[i] = query(x[i], y[t[i]]);
  printf("! %d\n", *std::min_element(t.begin(), t.end()));
  fflush(stdout);
  return 0;
}
