| #include <iostream> |
| #include <vector> |
| #include <algorithm> |
| #include <map> |
| #include <random> |
|
|
| using namespace std; |
|
|
| |
| int N; |
| long long K; |
| map<pair<int, int>, long long> memo; |
| int queries_count = 0; |
|
|
| |
| long long query(int r, int c) { |
| if (r < 1 || r > N || c < 1 || c > N) return 2e18; |
| if (memo.count({r, c})) return memo[{r, c}]; |
| |
| |
| if (queries_count >= 50000) return 2e18; |
|
|
| cout << "QUERY " << r << " " << c << endl; |
| long long val; |
| cin >> val; |
| memo[{r, c}] = val; |
| queries_count++; |
| return val; |
| } |
|
|
| int main() { |
| |
| ios_base::sync_with_stdio(false); |
| cin.tie(NULL); |
|
|
| if (!(cin >> N >> K)) return 0; |
|
|
| |
| |
| |
| vector<int> lo(N + 1, 1); |
| vector<int> hi(N + 1, N); |
| |
| |
| mt19937_64 rng(1337); |
|
|
| while (true) { |
| |
| long long active_size = 0; |
| vector<int> valid_rows; |
| for (int i = 1; i <= N; ++i) { |
| if (lo[i] <= hi[i]) { |
| active_size += (hi[i] - lo[i] + 1); |
| valid_rows.push_back(i); |
| } |
| } |
|
|
| |
| |
| if (active_size <= 2500 || (50000 - queries_count) <= active_size + 100) { |
| vector<long long> candidates; |
| candidates.reserve(active_size); |
| for (int r : valid_rows) { |
| for (int c = lo[r]; c <= hi[r]; ++c) { |
| candidates.push_back(query(r, c)); |
| } |
| } |
| sort(candidates.begin(), candidates.end()); |
| |
| |
| long long smaller_count = 0; |
| for (int i = 1; i <= N; ++i) { |
| smaller_count += (lo[i] - 1); |
| } |
| |
| long long index = K - smaller_count - 1; |
| if (index < 0) index = 0; |
| if (index >= candidates.size()) index = candidates.size() - 1; |
| |
| cout << "DONE " << candidates[index] << endl; |
| return 0; |
| } |
|
|
| |
| int samples_cnt = 25; |
| if (active_size < samples_cnt) samples_cnt = active_size; |
| |
| vector<long long> samples; |
| for (int s = 0; s < samples_cnt; ++s) { |
| long long idx = uniform_int_distribution<long long>(0, active_size - 1)(rng); |
| |
| int r_idx = -1, c_idx = -1; |
| long long current = 0; |
| for (int r : valid_rows) { |
| long long width = hi[r] - lo[r] + 1; |
| if (idx < current + width) { |
| r_idx = r; |
| c_idx = lo[r] + (idx - current); |
| break; |
| } |
| current += width; |
| } |
| if (r_idx != -1) samples.push_back(query(r_idx, c_idx)); |
| } |
| sort(samples.begin(), samples.end()); |
|
|
| |
| long long smaller_count_global = 0; |
| for (int i = 1; i <= N; ++i) smaller_count_global += (lo[i] - 1); |
| long long needed = K - smaller_count_global; |
| |
| double ratio = (double)needed / active_size; |
| int sample_idx = (int)(ratio * samples.size()); |
| if (sample_idx < 0) sample_idx = 0; |
| if (sample_idx >= samples.size()) sample_idx = samples.size() - 1; |
| |
| long long pivot = samples[sample_idx]; |
|
|
| |
| long long count_le = 0; |
| vector<int> p(N + 1); |
| |
| int c = N; |
| for (int r = 1; r <= N; ++r) { |
| count_le += (lo[r] - 1); |
| |
| |
| c = min(c, hi[r]); |
| |
| if (lo[r] > hi[r]) { |
| |
| p[r] = c; |
| } else { |
| |
| while (c >= lo[r]) { |
| long long val = query(r, c); |
| if (val > pivot) { |
| c--; |
| } else { |
| break; |
| } |
| } |
| p[r] = c; |
| count_le += (c - lo[r] + 1); |
| } |
| } |
| |
| |
| if (count_le < K) { |
| |
| |
| for (int r = 1; r <= N; ++r) { |
| if (lo[r] <= hi[r]) |
| lo[r] = max(lo[r], p[r] + 1); |
| } |
| } else { |
| |
| |
| for (int r = 1; r <= N; ++r) { |
| if (lo[r] <= hi[r]) |
| hi[r] = min(hi[r], p[r]); |
| } |
| } |
| } |
| return 0; |
| } |