import sys import io def flush_print(*args): """ 末尾改行と出力の flush を確実に行うためのヘルパー関数 """ # sys.stdout.write() と sys.stdout.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 find_P1_position_deterministically(N, a, b): """ 2N回のクエリで P_i=1 の位置 i1 を特定するロジック。 最も-1が少ない i を i1 の最有力候補とします。 """ neg_one_counts = {} # 2N回のクエリを実行 (i=1 から N) for i in range(1, N + 1): count = 0 # 基準点 a, b と i が異なる場合にクエリを実行 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 # min_count を持つ i を P_i=1 の位置 i1 として確定する if not neg_one_counts: return 1 # Nが小さい場合のフォールバック min_count = min(neg_one_counts.values()) # min_count の i を返す for i, count in neg_one_counts.items(): if count == min_count: return i # 1-indexed def restore_permutation(N): """N のテストケースの順列 P を復元するメインロジック""" # P を 1 から N の値を持つように 0-indexed で初期化 (P[i] は P_{i+1} の値) P = [0] * N # ---------------------------------------------------- # フェーズ 1: P_i1=1 の位置 i1 の特定 (2N 回のクエリ) # ---------------------------------------------------- a, b = 1, 2 # 基準点 # 2N 回のクエリを実行し、i1 を特定する i1 = find_P1_position_deterministically(N, a, b) P[i1 - 1] = 1 # P_i1 = 1 確定 # ---------------------------------------------------- # フェーズ 2: P 全体の復元 (N-1 回のクエリ) # ---------------------------------------------------- P_N_pos = -1 # P_N の位置 (1-indexed) transitions = {} # 遷移 j -> k を記録 {j: k} # i1 を基準として N-1 回のクエリを実行し、+1 遷移グラフを構築 for j in range(1, N + 1): if j == i1: continue k = query(i1, j) # Q(i1, j) を実行 if k == -1: # P_j = N が確定 P_N_pos = j P[j - 1] = N else: # P_k = P_j + 1 の遷移が確定 transitions[j] = k # ---------------------------------------------------- # フェーズ 3: +1 遷移の追跡による P の連鎖復元 # ---------------------------------------------------- current_pos = i1 current_val = 1 # P_i1=1 からスタートし、P_N-1 まで順番に値を確定させる while current_val < N: # current_pos は 1-indexed next_pos = transitions.get(current_pos) if next_pos is None: # P_N の手前でパスが途切れた場合 (P_N が既に確定済み) break current_val += 1 P[next_pos - 1] = current_val current_pos = next_pos # 復元された P を返す return P def main(): """メイン実行ループ: T回のテストケースを処理する""" # 1. T の読み込み (ジャッジが最初に T を出力) T_line = read_input() if not T_line: return try: T = int(T_line) except ValueError: return # 2. T 回のテストケース処理 for t in range(T): # N の読み込み (各テストケースの開始時にジャッジが出力) N_line = read_input() if not N_line: break N = int(N_line) # 順列の復元 (最大 3N-1 回のクエリがこの中で実行される) P_restored = restore_permutation(N) # 答えの出力 (2 P1 P2 ... PN) # P_restored は 1 から N の値を持つリスト flush_print(2, *P_restored) # 全てのテストケースが終了 sys.exit(0) # 実行 if __name__ == "__main__": main()