Problem: cf788_d
Difficulty: easy
Categories: search
Time limit: 3000 ms, memory limit: 256 MB

D. Finding lines

After some programming contest Roma decided to try himself in tourism. His home country Uzhlyandia is a Cartesian plane. He wants to walk along each of the Main Straight Lines in Uzhlyandia. It is known that each of these lines is a straight line parallel to one of the axes (i.e. it is described with the equation *x* = *a* or *y* = *a*, where *a* is integer called the coordinate of this line).

Roma lost his own map, so he should find out the coordinates of all lines at first. Uncle Anton agreed to help him, using the following rules:

* Initially Roma doesn't know the number of vertical and horizontal lines and their coordinates;
* Roma can announce integer coordinates of some point in Uzhlandia, and Anton then will tell him the minimum among the distances from the chosen point to each of the lines. However, since the coordinates of the lines don't exceed 108 by absolute value, Roma can't choose a point with coordinates exceeding 108 by absolute value.

Uncle Anton is in a hurry to the UOI (Uzhlandian Olympiad in Informatics), so he can only answer no more than 3·105 questions.

The problem is that Roma doesn't know how to find out the coordinates of the lines. Write a program that plays Roma's role and finds the coordinates.

Input

There is no input initially. Your program should make queries to get information.

It is guaranteed that the number of horizontal and vertical lines is at least 1 and less than or equal to 104 for each type.

Interaction

To make a query, print a line "0 x y" (-108 ≤ *x*, *y* ≤ 108), where *x* and *y* are the coordinates of the point. After each query you need to print end-of-line, make "flush" operation, and then read the answer to the query — the minimum among the distances prom this point to the Main Straight Lines of Uzhlyandia.

You can do no more than 3·105 queries.

When you are ready to print the answer, print three lines:

1. In the first line print "1 n m", where *n* is the number of vertical lines (parallel to *OY*), and *m* is the number of horizontal lines (parallel to *OX*).
2. In the second line print *n* integers *x*1, *x*2, ..., *x**n* — the coordinates of the vertical lines.
3. In the third line in the same format print *m* integers *y*1, *y*2, ..., *y**m* — the coordinates of the horizontal lines.

You can print coordinates in arbitrary order.

To make "flush", you can use (just after printing a query/answer and end-of-line):

* fflush(stdout) in C++;
* System.out.flush() in Java;
* stdout.flush() in Python;
* flush(output) in Pascal;
* see the documentation for other languages.

You will get Wrong Answer if you make more queries than allowed or make an invalid query.

You can get Idleness Limit Exceeded if you don't print anything or if you forget to flush the output.

If at any moment your program reads -1 as an answer, it should immediately exit normally (for example, by calling exit(0)). You will get Wrong Answer in this case, it means that you made more queries than allowed, or made an invalid query. If you ignore this, you can get other verdicts since your program will continue to read from a closed stream.

Example

Input

```
1  
1  
3  
2
```

Output

```
0 1 2  
0 -2 -2  
0 5 6  
0 -2 2  
1 1 2  
2  
0 -3
```

Note

The example test is

```
1 2  
2  
0 -3
```

The minimum distances are:

* from (1, 2) to *x* = 2;
* from ( - 2,  - 2) to *y* =  - 3;
* from (5, 6) to *x* = 2;
* from ( - 2, 2) to *y* = 0.

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

using namespace std;


static long long queries = 0;
static const long long query_limit = 300000;
static bool finished_logging = false;



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


static void finish_verdict(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();
    int m = inf.readInt();
    
    vector<int> true_x;
    true_x.reserve(n);
    for (int i = 0; i < n; ++i) {
        true_x.push_back(inf.readInt());
    }
    
    vector<int> true_y;
    true_y.reserve(m);
    for (int i = 0; i < m; ++i) {
        true_y.push_back(inf.readInt());
    }

    
    sort(true_x.begin(), true_x.end());
    sort(true_y.begin(), true_y.end());

    
    while (true) {
        string token;
        
        
        if (!(cin >> token)) {
            finish_verdict(_wa, "Unexpected EOF (solution exited without answer)");
        }

        
        
        
        bool is_query = (token == "0" || token == "?" || (token.size() > 0 && token[0] == '?'));
        bool is_answer = (token == "1" || token == "!" || (token.size() > 0 && token[0] == '!'));

        if (is_query) {
            queries++;
            
            if (queries > query_limit) {
                cout << -1 << endl; 
                finish_verdict(_wa, "Query limit exceeded");
            }

            
            int qx, qy;
            if (!(cin >> qx >> qy)) {
                finish_verdict(_wa, "Invalid query format (expected 2 integers)");
            }

            
            if (abs(qx) > 100000000 || abs(qy) > 100000000) {
                finish_verdict(_wa, "Query coordinates out of range [-10^8, 10^8]");
            }

            
            long long ans = 2000000000LL; 

            
            auto itx = lower_bound(true_x.begin(), true_x.end(), qx);
            if (itx != true_x.end()) {
                ans = min(ans, (long long)abs((long long)*itx - qx));
            }
            if (itx != true_x.begin()) {
                ans = min(ans, (long long)abs((long long)*prev(itx) - qx));
            }

            
            auto ity = lower_bound(true_y.begin(), true_y.end(), qy);
            if (ity != true_y.end()) {
                ans = min(ans, (long long)abs((long long)*ity - qy));
            }
            if (ity != true_y.begin()) {
                ans = min(ans, (long long)abs((long long)*prev(ity) - qy));
            }

            
            cout << ans << endl;
        } 
        else if (is_answer) {
            
            int an, am;
            if (!(cin >> an >> am)) {
                finish_verdict(_wa, "Invalid answer format (expected n m)");
            }
            
            
            if (an < 0 || an > 20000 || am < 0 || am > 20000) {
                finish_verdict(_wa, "Answer counts out of reasonable range");
            }
            
            vector<int> ax(an), ay(am);
            
            for (int i = 0; i < an; ++i) {
                if (!(cin >> ax[i])) finish_verdict(_wa, "Invalid answer format (reading x)");
            }
            
            for (int i = 0; i < am; ++i) {
                if (!(cin >> ay[i])) finish_verdict(_wa, "Invalid answer format (reading y)");
            }
            
            
            sort(ax.begin(), ax.end());
            sort(ay.begin(), ay.end());
            
            if (ax == true_x && ay == true_y) {
                finish_verdict(_ok, "Correct lines found");
            } else {
                finish_verdict(_wa, "Incorrect lines found");
            }
        } 
        else {
            
            finish_verdict(_wa, "Invalid token '" + token + "' (expected 0 or 1)");
        }
    }
    
    return 0;
}


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

using namespace std;


const int MIN_COORD = -100000000;
const int MAX_COORD = 100000000;
const long long HARD_CAP = 3000000; 


static long long queries = 0;
static long long query_limit = 300000; 


vector<int> hidden_x;
vector<int> hidden_y;


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


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



vector<int> generate_coords(int k, int seed_salt) {
    vector<int> res;
    set<int> taken;
    
    
    
    long long state = 5489LL * k + 7919LL * seed_salt + 12345;
    
    int attempts = 0;
    while(res.size() < (size_t)k) {
        attempts++;
        state = (state * 48271LL) % 2147483647LL;
        
        
        long long val = state % 200000001;
        val -= 100000000;
        
        if (taken.find((int)val) == taken.end()) {
            taken.insert((int)val);
            res.push_back((int)val);
        }
        
        
        if (attempts > k * 10 && res.size() < (size_t)k) {
            int needed = k - res.size();
            int start = MIN_COORD;
            while (needed > 0) {
                if (taken.find(start) == taken.end()) {
                    res.push_back(start);
                    needed--;
                }
                start++;
            }
            break;
        }
    }
    sort(res.begin(), res.end());
    return res;
}

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

    
    
    int n = inf.readInt(1, 10000, "n");
    int m = inf.readInt(1, 10000, "m");

    
    
    
    if (inf.seekEof()) {
        
        hidden_x = generate_coords(n, 1);
        hidden_y = generate_coords(m, 2);
    } else {
        
        for (int i = 0; i < n; i++) {
            hidden_x.push_back(inf.readInt(MIN_COORD, MAX_COORD, "x_i"));
        }
        for (int i = 0; i < m; i++) {
            hidden_y.push_back(inf.readInt(MIN_COORD, MAX_COORD, "y_i"));
        }
        sort(hidden_x.begin(), hidden_x.end());
        sort(hidden_y.begin(), hidden_y.end());
    }

    
    
    log_metrics();

    
    while (true) {
        
        string type_str;
        
        if (!(cin >> type_str)) {
            
            finish(_wa, "Unexpected end of stream (output closed?)");
        }
        
        if (type_str == "0") {
            
            long long x, y;
            if (!(cin >> x >> y)) {
                finish(_wa, "Invalid format for query type 0");
            }
            
            
            if (x < MIN_COORD || x > MAX_COORD || y < MIN_COORD || y > MAX_COORD) {
                finish(_wa, "Query coordinates out of bounds");
            }
            
            queries++;
            
            if (queries % 10000 == 0) log_metrics();

            
            if (queries > HARD_CAP) {
                finish(_pe, "Hard query limit exceeded");
            }
            
            
            long long min_dist = 2000000000LL; 
            
            
            auto it_x = lower_bound(hidden_x.begin(), hidden_x.end(), (int)x);
            if (it_x != hidden_x.end()) {
                min_dist = min(min_dist, abs((long long)*it_x - x));
            }
            if (it_x != hidden_x.begin()) {
                min_dist = min(min_dist, abs((long long)*prev(it_x) - x));
            }
            
            
            auto it_y = lower_bound(hidden_y.begin(), hidden_y.end(), (int)y);
            if (it_y != hidden_y.end()) {
                min_dist = min(min_dist, abs((long long)*it_y - y));
            }
            if (it_y != hidden_y.begin()) {
                min_dist = min(min_dist, abs((long long)*prev(it_y) - y));
            }
            
            cout << min_dist << endl; 
            
        } else if (type_str == "1") {
            
            int ans_n, ans_m;
            if (!(cin >> ans_n >> ans_m)) {
                finish(_wa, "Invalid format for answer type 1");
            }
            
            if (ans_n != (int)hidden_x.size() || ans_m != (int)hidden_y.size()) {
                finish(_wa, format("Incorrect counts: expected %d %d, got %d %d", 
                                   (int)hidden_x.size(), (int)hidden_y.size(), ans_n, ans_m));
            }
            
            vector<int> ans_x(ans_n), ans_y(ans_m);
            for (int i = 0; i < ans_n; i++) {
                if (!(cin >> ans_x[i])) finish(_wa, "Failed reading vertical lines answer");
            }
            for (int i = 0; i < ans_m; i++) {
                if (!(cin >> ans_y[i])) finish(_wa, "Failed reading horizontal lines answer");
            }
            
            sort(ans_x.begin(), ans_x.end());
            sort(ans_y.begin(), ans_y.end());
            
            if (ans_x != hidden_x) {
                finish(_wa, "Vertical lines incorrect");
            }
            if (ans_y != hidden_y) {
                finish(_wa, "Horizontal lines incorrect");
            }
            
            finish(_ok, "Correct");
            
        } else {
            finish(_wa, "Unknown command type (expected 0 or 1)");
        }
    }
    
    return 0;
}


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

using namespace std;


const int MIN_COORD = -100000000;
const int MAX_COORD = 100000000;
const int MIN_NM = 1;
const int MAX_NM = 10000;


vector<int> generate_coords(int k, int min_v, int max_v, int type) {
    vector<int> res;
    
    
    long long range_len = (long long)max_v - min_v + 1;
    if (range_len < k) {
        for (int i = 0; i < k; i++) res.push_back(min_v + i);
        return res;
    }

    if (type == 1) { 
        set<int> taken;
        int center = rnd.next(min_v, max_v);
        
        int radius = rnd.next(k, 200000); 
        int l = max(min_v, center - radius);
        int r = min(max_v, center + radius);
        
        
        if ((long long)r - l + 1 < k) {
            l = min_v; r = max_v;
        }
        
        
        if ((long long)r - l + 1 < 2LL * k) {
             vector<int> p(r - l + 1);
             iota(p.begin(), p.end(), l);
             shuffle(p.begin(), p.end()); 
             
             
             res.clear();
             
             for (int i = 0; i < k; i++) {
                 
                 int j = rnd.next(i, (int)p.size() - 1);
                 swap(p[i], p[j]);
                 res.push_back(p[i]);
             }
        } else {
             
             while ((int)taken.size() < k) {
                int x = rnd.next(l, r);
                if (taken.insert(x).second) res.push_back(x);
             }
        }
    } else if (type == 2) { 
        int start = rnd.next(min_v, max_v - k + 1);
        for (int i = 0; i < k; ++i) {
            res.push_back(start + i);
        }
    } else if (type == 3) { 
        
        long long total_gap = (long long)max_v - min_v + 1 - k;
        vector<long long> gaps = rnd.partition(k + 1, total_gap);
        long long current = min_v;
        for (int i = 0; i < k; i++) {
            current += gaps[i];
            res.push_back((int)current);
            current++; 
        }
    } else { 
        set<int> taken;
        while ((int)taken.size() < k) {
            int x = rnd.next(min_v, max_v);
            if (taken.insert(x).second) res.push_back(x);
        }
    }
    
    sort(res.begin(), res.end());
    return res;
}

int main(int argc, char* argv[]) {
    registerGen(argc, argv, 1);
    
    
    string mode = opt<string>("mode", "non");
    
    
    int seed_val = 0;
    try {
        if (argc > 1) seed_val = stoi(argv[1]);
    } catch (...) {
        seed_val = 100;
    }

    
    int n, m;
    if (seed_val == 1) {
        n = 1; m = 1;
    } else if (seed_val == 2) {
        n = 1; m = MAX_NM;
    } else if (seed_val == 3) {
        n = MAX_NM; m = 1;
    } else if (seed_val == 4) {
        n = 100; m = 100;
    } else if (seed_val == 5) {
        n = MAX_NM; m = MAX_NM;
    } else {
        
        
        int dice = rnd.next(100);
        if (dice < 10) { 
            n = rnd.next(1, 10);
            m = rnd.next(1, 10);
        } else if (dice < 30) { 
            n = rnd.next(10, 100);
            m = rnd.next(10, 100);
        } else if (dice < 60) { 
             n = rnd.next(100, 5000);
             m = rnd.next(100, 5000);
        } else { 
             n = rnd.next(5000, MAX_NM);
             m = rnd.next(5000, MAX_NM);
        }
    }

    
    
    if (mode == "adp") {
        cout << n << " " << m << endl;
        return 0;
    }

    
    vector<int> xs, ys;

    
    if (seed_val == 1) {
        xs = {0};
        ys = {0};
    } else if (seed_val == 2) {
        xs = {-100000000};
        ys = generate_coords(m, MIN_COORD, MAX_COORD, 0);
    } else if (seed_val == 3) {
        xs = generate_coords(n, MIN_COORD, MAX_COORD, 0);
        ys = {100000000};
    } else {
        
        
        int typeX = (seed_val == 4) ? 1 : (rnd.next(10) < 3 ? 2 : (rnd.next(10) < 3 ? 3 : 0));
        int typeY = (seed_val == 4) ? 1 : (rnd.next(10) < 3 ? 2 : (rnd.next(10) < 3 ? 3 : 0));
        
        
        if (seed_val > 5 && typeX == 2 && typeY == 2) typeY = 0;

        xs = generate_coords(n, MIN_COORD, MAX_COORD, typeX);
        ys = generate_coords(m, MIN_COORD, MAX_COORD, typeY);
    }

    
    cout << n << " " << m << endl;
    
    
    for (int i = 0; i < n; i++) {
        cout << xs[i] << (i == n - 1 ? "" : " ");
    }
    cout << endl;
    
    
    for (int i = 0; i < m; i++) {
        cout << ys[i] << (i == m - 1 ? "" : " ");
    }
    cout << endl;

    return 0;
}