#include <bits/stdc++.h>
using namespace std;
inline int min(int a, int b) { return (a < b ? a : b); }
inline int max(int a, int b) { return (a > b ? a : b); }
struct Interval {
  int a, b;
};
int length(Interval& one) { return one.b - one.a; }
bool operator<(Interval one, Interval other) {
  return length(one) < length(other);
}
int ask(int x, int y) {
  int k;
  printf("0 %d %d\n", x, y);
  fflush(stdout);
  scanf("%d", &k);
  if (k == -1) exit(0);
  return k;
}
int main() {
  Interval big;
  big.a = -1e8;
  big.b = 1e8;
  priority_queue<Interval> pq;
  pq.push(big);
  vector<int> linesx, linesy;
  set<int> check;
  Interval x, nx;
  int empty, dist, d;
  bool found_empty = false;
  while (not pq.empty()) {
    x = pq.top();
    pq.pop();
    if (length(x) == 0) {
      check.insert(x.a);
    } else if (length(x) == 1) {
      check.insert(x.a);
      check.insert(x.b);
    } else {
      d = (x.b + x.a) / 2;
      dist = ask(d, d);
      if (!found_empty && dist > 0) {
        empty = d;
        found_empty = true;
      }
      if (d + dist <= 1e8) check.insert(d + dist);
      if (d - dist >= -1e8) check.insert(d - dist);
      nx.a = x.a;
      nx.b = max(d - 1 - dist, -1e8);
      if (nx.a <= nx.b) pq.push(nx);
      nx.a = min(d + 1 + dist, 1e8);
      nx.b = x.b;
      if (nx.a <= nx.b) pq.push(nx);
    }
  }
  set<int>::iterator sit = check.begin();
  for (; sit != check.end(); ++sit) {
    if (ask(*sit, empty) == 0) {
      linesx.push_back(*sit);
    }
    if (ask(empty, *sit) == 0) {
      linesy.push_back(*sit);
    }
  }
  printf("1 %d %d\n", linesx.size(), linesy.size());
  for (int i = 0; i < linesx.size(); ++i) {
    printf("%d ", linesx[i]);
  }
  printf("\n");
  for (int i = 0; i < linesy.size(); ++i) {
    printf("%d ", linesy[i]);
  }
  printf("\n");
  return 0;
}
