#include using namespace std; using ll = long long; const ll INF = (1LL << 62); struct Item { ll val; int idx; // original 1-indexed index }; struct Solver { bool isAlice; int N, M; vector S; int da = 0, db = 0; // discarded count from A / B int k_rank = 0; int lenA() const { return N - da; } int lenB() const { return M - db; } int myLen() const { return isAlice ? lenA() : lenB(); } int myOffset() const { return isAlice ? da : db; } int dummyIndex() const { return S[0].idx; } ll shareIndex(int idx) { cout << "share " << idx << '\n'; cout.flush(); ll v; if (!(cin >> v)) exit(0); if (v == -1) exit(0); return v; } void answerAndContinue(ll ans) { cout << "answer " << ans << '\n'; cout.flush(); int r; if (!(cin >> r)) exit(0); if (r == -1) exit(0); } // rank-th value/index in my remaining sequence. // rank is 1-indexed. pair myRankInfo(int rank) const { int len = myLen(); int off = myOffset(); if (1 <= rank && rank <= len) { const Item &it = S[off + rank - 1]; return {it.idx, it.val}; } else { return {dummyIndex(), INF}; } } // One communication round. // // Alice sends rankA-th remaining A value. // Bob sends rankB-th remaining B value. // // If that rank does not exist, that player sends a dummy index, // and both players logically treat the value as INF. pair exchangeRanks(int rankA, int rankB) { bool validA = (1 <= rankA && rankA <= lenA()); bool validB = (1 <= rankB && rankB <= lenB()); if (isAlice) { auto [idx, myVal] = myRankInfo(rankA); ll recv = shareIndex(idx); ll aVal = validA ? myVal : INF; ll bVal = validB ? recv : INF; return {aVal, bVal}; } else { auto [idx, myVal] = myRankInfo(rankB); ll recv = shareIndex(idx); ll aVal = validA ? recv : INF; ll bVal = validB ? myVal : INF; return {aVal, bVal}; } } // One side is empty. // The owner of the answer sends the answer value once. void finishFromSide(bool answerIsInAlice, int rank) { ll ans = -1; int idx = dummyIndex(); if (isAlice == answerIsInAlice) { auto [sendIdx, val] = myRankInfo(rank); idx = sendIdx; ans = val; } ll recv = shareIndex(idx); if (isAlice != answerIsInAlice) { ans = recv; } answerAndContinue(ans); } void solveCase() { sort(S.begin(), S.end(), [](const Item &a, const Item &b) { if (a.val != b.val) return a.val < b.val; return a.idx < b.idx; }); da = db = 0; k_rank = (N + M + 1) / 2; while (true) { if (lenA() == 0) { finishFromSide(false, k_rank); // answer is in Bob return; } if (lenB() == 0) { finishFromSide(true, k_rank); // answer is in Alice return; } if (k_rank <= 3) { vector cand; for (int r = 1; r <= k_rank; r++) { auto [av, bv] = exchangeRanks(r, r); if (av < INF) cand.push_back(av); if (bv < INF) cand.push_back(bv); } sort(cand.begin(), cand.end()); answerAndContinue(cand[k_rank - 1]); return; } int t = k_rank / 2; int p = min(t, lenA()); int q = min(t, lenB()); auto [ap, bq] = exchangeRanks(p, q); // 重複ありでも、等号時は Alice 側を捨てる、と固定すればよい。 if (ap <= bq) { da += p; k_rank -= p; } else { db += q; k_rank -= q; } } } }; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int T, Q; string player; cin >> T >> Q; cin >> player; bool isAlice = (player == "Alice"); for (int tc = 0; tc < T; tc++) { int N, M; cin >> N >> M; int L = isAlice ? N : M; vector S(L); for (int i = 0; i < L; i++) { cin >> S[i].val; S[i].idx = i + 1; } Solver solver; solver.isAlice = isAlice; solver.N = N; solver.M = M; solver.S = move(S); solver.solveCase(); } return 0; }