# ai回答2 import sys def flush_print(*args): """ 末尾改行と出力の flush を確実に行うためのヘルパー関数 """ output = ' '.join(map(str, args)) sys.stdout.write(output + '\n') sys.stdout.flush() def read_input(): """ 標準入力から一行読み込み、EOF やエラーで終了します。""" try: line = sys.stdin.readline() if not line: sys.exit(0) return line.strip() except Exception: sys.exit(0) def query(i, j): """ クエリ Q(i, j) を実行し、ジャッジからの結果 k または -1 を受け取る。""" if i == j: # プログラム側で i != j を保証しているため、ここは通常発生しない raise ValueError("Query constraint violation: i must not equal j.") # クエリプロトコル: 1 i j を出力 flush_print(1, i, j) # ジャッジからの返答 k を読み込む try: response = read_input() return int(response) except Exception: sys.exit(0) def restore_permutation(N): """N のテストケースの順列 P を復元するメインロジック""" # P を 1 から N の値を持つように 0-indexed で初期化 P = [0] * N # ---------------------------------------------------- # フェーズ 1: P_i1=1 の候補セット S_safe の特定 (2N 回のクエリ) # ---------------------------------------------------- a, b = 1, 2 # 基準点 neg_one_counts = {} # 2N回のクエリを実行 (i=1 から N)し、候補を絞り込む for i in range(1, N + 1): count = 0 if i != a: if query(i, a) == -1: count += 1 if i != b: if query(i, b) == -1: count += 1 neg_one_counts[i] = count # 最小の -1 カウントを持つ全ての i を候補とする (S_safe) if not neg_one_counts: return [1] * N # フォールバック min_count = min(neg_one_counts.values()) candidates = [i for i, count in neg_one_counts.items() if count == min_count] # ---------------------------------------------------- # フェーズ 2: S_safe の動的検証 (残りの N-1 回のクエリ枠を使用) # ---------------------------------------------------- # P_i=1 の真の位置は、S_safe の中で唯一矛盾なくパスを構築できる for i_candidate in candidates: # 候補 i* を P_i=1 と仮定し、N-1 回のクエリ内で検証を試みる P_temp = [0] * N P_temp[i_candidate - 1] = 1 # 暫定確定: P_i* = 1 transitions = {} is_consistent = True # N-1 回のクエリを実行し、矛盾がないかチェック (i*を i1 として検証) # i* を使ってクエリを再実行し、矛盾が出たら即座に次の候補へ移行する for j in range(1, N + 1): if j == i_candidate: continue k = query(i_candidate, j) if k == -1: # P_j = N が確定 (ただし、暫定順列 P_temp 内で) if P_temp[j - 1] != 0: # 既に P_j に値が割り当てられており、それが N でない場合、矛盾 if P_temp[j - 1] != N: is_consistent = False; break else: P_temp[j - 1] = N else: # P_k = P_j + 1 の遷移が確定 # 矛盾チェック1: k の位置は既に確定した値と重複しないか? if P_temp[k - 1] != 0: # k の値が既に確定済みなら、その値が P_j + 1 と一致するか検証 # この時点では P_j の値は不明なため、より複雑なチェックが必要。 # 最も簡単なのは遷移を記録し、後でパスが閉じるか検証すること。 pass transitions[j] = k if not is_consistent: continue # 矛盾が見つかったので次の候補へ # ---------------------------------------------------- # パス追跡による最終検証と P の確定 # ---------------------------------------------------- # 矛盾なく N-1 クエリを実行できた場合、パス追跡で順列を完成させる current_pos = i_candidate current_val = 1 while current_val < N: next_pos = transitions.get(current_pos) if next_pos is None: # パスが途中で途切れたか、P_N に到達した。 break current_val += 1 # 矛盾チェック2: 既に値が割り当てられている位置で重複が発生しないか if P_temp[next_pos - 1] != 0 and P_temp[next_pos - 1] != current_val: is_consistent = False; break P_temp[next_pos - 1] = current_val current_pos = next_pos # 矛盾なく全ての値が確定したか (N個全てが非ゼロか) if is_consistent and all(v != 0 for v in P_temp): return P_temp # 真の順列 P を発見! # 論理的にはここに到達しない (到達した場合、アルゴリズムの前提が破綻) return [1] * N # フォールバック def main(): """メイン実行ループ: T回のテストケースを処理する""" try: # 1. T の読み込み T_line = read_input() if not T_line: return T = int(T_line) except Exception: return for t in range(T): # 2. N の読み込み N_line = read_input() if not N_line: break N = int(N_line) # 順列の復元 (この中でクエリが実行される) P_restored = restore_permutation(N) # 3. 答えの出力 (2 P1 P2 ... PN) flush_print(2, *P_restored) sys.exit(0) # 実行 if __name__ == "__main__": main()