#!/usr/bin/env pypy3 import sys def query(l, r, lp, rp): """ 問題のプロトコルに従い,クエリ "? l r lp rp" を出力して, ジャッジからの応答を整数で返す。 クエリは A[l,r] と A[lp,rp] の辞書順大小の比較を行うもので, 応答は 1 → A[l,r] < A[lp,rp] が真 0 → それ以外(A[l,r] ≥ A[lp,rp]) を意味する。 """ print(f"? {l} {r} {lp} {rp}") sys.stdout.flush() line = sys.stdin.readline().strip() if not line: sys.exit(0) x = int(line) if x == -1: sys.exit(0) return x def main(): # 最初に N, Q を読む(問題では N=1000, Q=1500 固定) s = sys.stdin.readline().strip() if not s: sys.exit(0) parts = s.split() N = int(parts[0]) Q = int(parts[1]) # S: 集合 { i のうち,ペア比較で A[i,N] が小さいほう } # T: 集合 { i のうち,ペア比較で A[i,N] が大きいほう } S = [] T = [] # ペアごとの比較:各 i=1,2,...,floor(N/2) for i in range(1, N//2 + 1): i1 = 2 * i - 1 i2 = 2 * i # クエリ: A[i1,N] と A[i2,N] の比較 resp = query(i1, N, i2, N) if resp == 1: # A[i1,N] < A[i2,N] → i1 を S, i2 を T に入れる S.append(i1) T.append(i2) else: # resp == 0 なら A[i1,N] ≥ A[i2,N] → i2 を S, i1 を T に入れる S.append(i2) T.append(i1) # N が奇数の場合は,余ったインデックス N を両方に追加 if N % 2 == 1: S.append(N) T.append(N) # S 内で線形探索して,辞書順最小となる A[i,N] を与えるインデックスを求める # 初期候補 cand_min = S[0] for i in S[1:]: # 比較: cand_min,N と i,N resp = query(cand_min, N, i, N) # resp == 1 のときは A[cand_min,N] < A[i,N] なので cand_min のほうが小さい → そのまま # resp == 0 なら更新 if resp == 0: cand_min = i # T 内で線形探索して,辞書順最大となる A[i,N] を与えるインデックスを求める cand_max = T[0] for i in T[1:]: # 比較: cand_max,N と i,N resp = query(cand_max, N, i, N) # resp == 1 なら A[cand_max,N] < A[i,N] → i のほうが大きい,更新 if resp == 1: cand_max = i # resp == 0 のときは cand_max のほうが大きい(または同値)ので更新なし # 答えの部分文字列は,事実より # 辞書順最小のものは A[cand_min,cand_min] (= (A[cand_min])) # 辞書順最大のものは A[cand_max,N] print(f"! {cand_min} {cand_min} {cand_max} {N}") sys.stdout.flush() if __name__ == '__main__': main()