Problem: abc269_e
Difficulty: easy
Categories: search
Time limit: 2000 ms, memory limit: 1024 MB

### Problem Statement

**This is an interactive task** (where your program interacts with the judge's program via input and output).

We have an $N$-by-$N$ chessboard and $N$ rooks. Below, the square at the $i$-th row from the top and $j$-th column from the left is denoted by $(i, j)$.  
Consider placing the rooks on squares of the chessboard. Here, you have to place the rooks so that all of the following conditions are satisfied.

* No row contains two or more rooks.
* No column contains two or more rooks.

Now, $N-1$ rooks are placed on the chessboard so that all of the above conditions are satisfied. You will choose a square that is not occupied by a rook and place a rook on that square. (It can be proved that there is at least one square on which a rook can be placed under the conditions.)

However, you cannot directly see which squares of the chessboard are occupied by a rook.  
Instead, you may ask at most $20$ questions to the judge in the following manner.

* You choose integers $A$, $B$, $C$, and $D$ such that $1 \leq A \leq B \leq N, 1 \leq C \leq D \leq N$, and ask the number of rooks in the rectangular region formed by the squares $(i, j)$ such that $A \leq i \leq B, C \leq j \leq D$.

Find a square to place a rook.

### Constraints

* $2 \leq N \leq 10^3$
* $N$ is an integer.

### Input and Output

This is an interactive task (where your program interacts with the judge's program via input and output).

First, receive the size of the chessboard, $N$, from Standard Input.

```
$N$
```

Next, repeat asking a question until you find a square to place a rook.  
A question should be printed to Standard Output in the following format:

```
$?$ $A$ $B$ $C$ $D$
```

The response will be given from Standard Input in the following format:

```
$T$
```

Here, $T$ is the response to the question, or `-1` if the question is invalid or more than $20$ questions have been asked.

When the judge returns `-1`, the submission is already regarded as incorrect. In this case, terminate the program immediately.

When you find a square to place a rook, let $(X, Y)$ be that square and print an answer in the following format. Then, terminate the program immediately.

```
$!$ $X$ $Y$
```

If there are multiple appropriate answers, any of them will be accepted.

### Notes

* **Each time you print something, end it with a newline and then flush Standard Output. Otherwise, you may get a TLE verdict.**
* **If an invalid output is printed during the interaction, the verdict will be indeterminate.**
* Terminate the program immediately after printing an answer. Otherwise, the verdict will be indeterminate.

### Sample Interaction

Below is an interaction where $N=3$ and the rooks are placed on $(1, 2)$ and $(2, 1)$.

| Input | Output | Description |
| --- | --- | --- |
| `3` |  | Judge first gives the integer $N$. |
|  | `? 1 2 1 3` | Participant asks a question with $(A,B,C,D)=(1,2,1,3)$. |
| `2` |  | Judge returns the answer to the question, which is $2$. |
|  | `? 2 3 1 1` | Participant asks a question with $(A,B,C,D)=(2,3,1,1)$. |
| `1` |  | Judge returns the answer to the question, which is $1$. |
|  | `? 1 3 3 3` | Participant asks a question with $(A,B,C,D)=(1,3,3,3)$. |
| `0` |  | Judge returns the answer to the question, which is $0$. |
|  | `! 3 3` | Participant finds the answer to be $(3, 3)$ and prints it. |

Non-adaptive interactor (C++):
#include "testlib.h"
#include <bits/stdc++.h>
using namespace std;


static long long queries = 0;
static long long query_limit = 20;


static void log_metrics() {
    try {
        tout << "queries=" << queries << endl;
        tout << "query_limit=" << query_limit << endl;
    } catch (...) {
        
    }
}


static void finish(TResult verdict, const string& msg) {
    log_metrics();
    quitf(verdict, "%s", msg.c_str());
}

int main(int argc, char** argv) {
    registerInteraction(argc, argv);
    atexit(log_metrics); 

    
    int N = inf.readInt();
    
    
    vector<pair<int, int>> rooks;
    vector<bool> r_occ(N + 1, false);
    vector<bool> c_occ(N + 1, false);
    
    for (int i = 0; i < N - 1; ++i) {
        int r = inf.readInt();
        int c = inf.readInt();
        rooks.push_back({r, c});
        r_occ[r] = true;
        c_occ[c] = true;
    }
    
    
    int ans_r = -1, ans_c = -1;
    for (int i = 1; i <= N; ++i) {
        if (!r_occ[i]) ans_r = i;
        if (!c_occ[i]) ans_c = i;
    }
    
    if (ans_r == -1 || ans_c == -1) {
        quitf(_fail, "Generator error: No empty row/column found");
    }

    
    cout << N << endl;

    
    
    string token;
    while (cin >> token) {
        bool is_query = false;
        bool is_answer = false;
        vector<int> args;

        if (!token.empty() && token[0] == '!') {
            is_answer = true;
            
            if (token.size() > 1) {
                try {
                    args.push_back(stoi(token.substr(1)));
                } catch (...) {
                    finish(_pe, "Invalid format: '!' followed by non-integer: " + token);
                }
            }
        } else if (!token.empty() && token[0] == '?') {
            is_query = true;
            
            if (token.size() > 1) {
                try {
                    args.push_back(stoi(token.substr(1)));
                } catch (...) {
                    finish(_pe, "Invalid format: '?' followed by non-integer: " + token);
                }
            }
        } else {
            
            try {
                size_t idx;
                int val = stoi(token, &idx);
                if (idx != token.size()) {
                    finish(_pe, "Invalid token (expected integer, '?', or '!'): " + token);
                }
                args.push_back(val);
                is_query = true;
            } catch (...) {
                finish(_pe, "Invalid token (not integer/!/?): " + token);
            }
        }

        if (is_answer) {
            
            while (args.size() < 2) {
                string t;
                if (!(cin >> t)) finish(_pe, "Unexpected EOF reading answer coordinates");
                try {
                    args.push_back(stoi(t));
                } catch (...) {
                    finish(_pe, "Invalid integer in answer coordinate: " + t);
                }
            }
            
            int r = args[0];
            int c = args[1];
            
            if (r == ans_r && c == ans_c) {
                finish(_ok, "Correct");
            } else {
                finish(_wa, "Wrong answer: expected " + to_string(ans_r) + " " + to_string(ans_c) 
                            + ", got " + to_string(r) + " " + to_string(c));
            }
            
        } else {
            
            while (args.size() < 4) {
                string t;
                if (!(cin >> t)) finish(_pe, "Unexpected EOF reading query parameters");
                try {
                    args.push_back(stoi(t));
                } catch (...) {
                    finish(_pe, "Invalid integer in query parameters: " + t);
                }
            }
            
            queries++;
            
            
            if (queries > query_limit) {
                cout << -1 << endl;
                finish(_wa, "Query limit exceeded");
            }
            
            int A = args[0];
            int B = args[1];
            int C = args[2];
            int D = args[3];
            
            
            bool invalid = false;
            if (A < 1 || A > N || B < 1 || B > N || A > B) invalid = true;
            if (C < 1 || C > N || D < 1 || D > N || C > D) invalid = true;
            
            if (invalid) {
                cout << -1 << endl;
                finish(_wa, "Invalid query range: " + to_string(A) + " " + to_string(B) + " " 
                            + to_string(C) + " " + to_string(D));
            }
            
            
            int cnt = 0;
            for (auto& p : rooks) {
                if (p.first >= A && p.first <= B && p.second >= C && p.second <= D) {
                    cnt++;
                }
            }
            cout << cnt << endl;
            
            
            if (queries % 5 == 0) log_metrics();
        }
    }
    
    
    finish(_pe, "Program exited without providing an answer");
    return 0;
}


Adaptive interactor (C++):
#include "testlib.h"
#include <bits/stdc++.h>
using namespace std;




int queries = 0;
const int query_limit = 20;   


void log_metrics() {
    try {
        tout << "queries=" << queries << endl;
        tout << "query_limit=" << query_limit << endl;
    } catch (...) {}
}


void finish(TResult verdict, string msg) {
    log_metrics();
    quitf(verdict, "%s", msg.c_str());
}


int N;
bool adaptive_mode = false;


vector<pair<int, int>> rooks; 
int target_X = -1; 
int target_Y = -1; 



vector<int> candX; 
vector<int> candY;
bool collapsed = false; 






int count_rooks_fixed(int A, int B, int C, int D, const vector<pair<int, int>>& current_rooks) {
    int cnt = 0;
    for (auto p : current_rooks) {
        if (p.first >= A && p.first <= B && p.second >= C && p.second <= D) {
            cnt++;
        }
    }
    return cnt;
}



int count_rooks_collapsed(int A, int B, int C, int D, int mx, int my) {
    
    
    
    
    int cnt = 0;
    int c_ptr = 1;
    for (int r = 1; r <= N; r++) {
        if (r == mx) continue;
        while (c_ptr == my) c_ptr++;
        int c = c_ptr;
        c_ptr++;
        
        if (r >= A && r <= B && c >= C && c <= D) {
            cnt++;
        }
    }
    return cnt;
}




int main(int argc, char** argv) {
    registerInteraction(argc, argv);
    atexit(log_metrics);

    
    N = inf.readInt();
    inf.skipBlanks(); 
    
    if (inf.eof()) {
        
        adaptive_mode = true;
        for (int i = 1; i <= N; i++) {
            candX.push_back(i);
            candY.push_back(i);
        }
    } else {
        
        adaptive_mode = false;
        vector<bool> row_has(N + 1, false);
        vector<bool> col_has(N + 1, false);
        for (int i = 0; i < N - 1; i++) {
            int r = inf.readInt();
            int c = inf.readInt();
            rooks.push_back({r, c});
            row_has[r] = true;
            col_has[c] = true;
        }
        for (int i = 1; i <= N; i++) {
            if (!row_has[i]) target_X = i;
            if (!col_has[i]) target_Y = i;
        }
    }

    
    cout << N << endl;

    
    while (true) {
        char type;
        
        if (!(cin >> type)) break; 

        if (type == '?') {
            int A, B, C, D;
            if (!(cin >> A >> B >> C >> D)) finish(_pe, "Invalid query format");

            queries++;
            
            if (queries > 200) finish(_pe, "Too many queries (hard cap)");

            
            bool valid = (1 <= A && A <= B && B <= N && 1 <= C && C <= D && D <= N);
            
            
            if (!valid || queries > query_limit) {
                cout << -1 << endl;
                if (!valid) finish(_wa, "Query coordinates out of bounds");
                else finish(_wa, "Query limit exceeded");
            }

            int ans = 0;

            if (!adaptive_mode) {
                ans = count_rooks_fixed(A, B, C, D, rooks);
            } else {
                
                if (collapsed) {
                    
                    ans = count_rooks_collapsed(A, B, C, D, candX[0], candY[0]);
                } else {
                    bool is_row_query = (C == 1 && D == N);
                    bool is_col_query = (A == 1 && B == N);

                    if (is_row_query) {
                        
                        
                        
                        int len = B - A + 1;
                        int ans0 = len;
                        int ans1 = len - 1;

                        
                        int count0 = 0; 
                        int count1 = 0; 
                        for (int x : candX) {
                            if (x < A || x > B) count0++;
                            else count1++;
                        }

                        
                        if (count1 > count0) {
                            ans = ans1;
                            vector<int> nextX;
                            for (int x : candX) if (x >= A && x <= B) nextX.push_back(x);
                            candX = nextX;
                        } else {
                            ans = ans0;
                            vector<int> nextX;
                            for (int x : candX) if (x < A || x > B) nextX.push_back(x);
                            candX = nextX;
                        }
                    } 
                    else if (is_col_query) {
                        
                        int len = D - C + 1;
                        int ans0 = len;
                        int ans1 = len - 1;

                        int count0 = 0; 
                        int count1 = 0;
                        for (int y : candY) {
                            if (y < C || y > D) count0++;
                            else count1++;
                        }

                        if (count1 > count0) {
                            ans = ans1;
                            vector<int> nextY;
                            for (int y : candY) if (y >= C && y <= D) nextY.push_back(y);
                            candY = nextY;
                        } else {
                            ans = ans0;
                            vector<int> nextY;
                            for (int y : candY) if (y < C || y > D) nextY.push_back(y);
                            candY = nextY;
                        }
                    } 
                    else {
                        
                        
                        collapsed = true;
                        int finalX = candX[0];
                        int finalY = candY[0];
                        candX = {finalX};
                        candY = {finalY};
                        ans = count_rooks_collapsed(A, B, C, D, finalX, finalY);
                    }
                }
            }
            cout << ans << endl; 

        } else if (type == '!') {
            int X, Y;
            if (!(cin >> X >> Y)) finish(_pe, "Invalid answer format");

            bool ok = false;
            if (!adaptive_mode) {
                ok = (X == target_X && Y == target_Y);
            } else {
                
                
                
                
                bool x_in = false; 
                for (int x : candX) if (x == X) x_in = true;
                bool y_in = false;
                for (int y : candY) if (y == Y) y_in = true;
                ok = (x_in && y_in);
            }

            if (ok) finish(_ok, "Correct");
            else finish(_wa, "Incorrect square");

        } else {
            finish(_pe, "Invalid token expected '?' or '!'");
        }
    }

    return 0;
}


Test generator (C++):
#include "testlib.h"
#include <bits/stdc++.h>

using namespace std;

int main(int argc, char* argv[]) {
    registerGen(argc, argv, 1);

    
    string mode = opt<string>("mode", "non");

    
    
    long long seed_val = 0;
    if (argc > 1) {
        string s = argv[1];
        bool is_num = !s.empty();
        for (char c : s) {
            if (!isdigit(c)) {
                is_num = false;
                break;
            }
        }
        if (is_num) {
            seed_val = atoll(s.c_str());
        }
    }

    
    int N;
    if (seed_val == 1) {
        N = 2; 
    } else if (seed_val == 2) {
        N = 3; 
    } else if (seed_val == 3) {
        N = 1000; 
    } else {
        
        N = rnd.next(2, 1000);
    }

    if (mode == "adp") {
        
        
        cout << N << endl;
    } else {
        
        
        
        
        cout << N << endl;

        int X = rnd.next(1, N); 
        int Y = rnd.next(1, N); 

        
        vector<int> rows;
        vector<int> cols;
        for (int i = 1; i <= N; i++) {
            if (i != X) rows.push_back(i);
            if (i != Y) cols.push_back(i);
        }

        
        shuffle(cols.begin(), cols.end());

        vector<pair<int, int>> rooks;
        for (int i = 0; i < N - 1; i++) {
            rooks.push_back({rows[i], cols[i]});
        }

        
        shuffle(rooks.begin(), rooks.end());

        for (const auto& p : rooks) {
            cout << p.first << " " << p.second << endl;
        }
    }

    return 0;
}