#include<vector>
#include<unordered_map>
#include<algorithm>
class Compression {
 public:
  Compression(const std::vector<int>& list) : value_(list) {
    std::sort(begin(value_), end(value_));
    value_.erase(std::unique(begin(value_), end(value_)), end(value_));
    for(int i = 0; i < value_.size(); ++i) index_[value_[i]] = i;
  }
  int size() const {return value_.size();}
  int index(const int v) const {return index_.at(v);}
  int operator[](const int i) const {return value_.at(i);}
 private:
  std::unordered_map<int, int> index_;
  std::vector<int> value_;
};

#include<bits/stdc++.h>
using namespace std;

class SegmentTree {
 public:
  explicit SegmentTree(int n) : size_(1) {
    while(size_ < n) size_ <<= 1;
    v_.assign(size_ << 1, set<int>());
  }
  void update(int a, int b, int v) {update(a, b + 1, v, 1, 0, size_);}
  bool find(int a, int b, int c, int d) const {return find(a, b + 1, c, d, 1, 0, size_);}
 private:
  int left_child(int k) const {return k << 1;}
  int right_child(int k) const {return (k << 1) + 1;}
  void update(int a, int b, int v, int k, int l, int r) {
    if(b <= l || r <= a) return;
    if(a <= l && r <= b) {v_.at(k).insert(v); return;}
    update(a, b, v, left_child(k),  l, (l+r)/2);
    update(a, b, v, right_child(k), (l+r)/2, r);
  }
  bool find(int a, int b, int c, int d, int k, int l, int r) const {
    if(b <= l || r <= a) return false;
    if(v_.at(k).lower_bound(c) != v_.at(k).upper_bound(d)) return true;
    if(a <= l && r <= b) return false;
    auto vl = find(a, b, c, d, left_child(k),  l, (l+r)/2);
    auto vr = find(a, b, c, d, right_child(k), (l+r)/2, r);
    return vl || vr;
  }
  int size_;
  vector<set<int>> v_;
};

int main() {
  int N;
  cin >> N;

  vector<int> px(N), py(N), qx(N), qy(N);
  for(int i = 0; i < N; ++i) {
    cin >> px[i] >> py[i] >> qx[i] >> qy[i];
    if(px[i] > qx[i]) swap(px[i], qx[i]);
    if(py[i] > qy[i]) swap(py[i], qy[i]);
  }

  vector<int> x, y;
  for(auto c: {px, qx}) for(auto i: c) x.emplace_back(i);
  for(auto c: {py, qy}) for(auto i: c) y.emplace_back(i);
  Compression cx(x), cy(y);
  for(auto c: {&px, &qx}) for(auto& i: *c) i = cx.index(i);
  for(auto c: {&py, &qy}) for(auto& i: *c) i = cy.index(i);

  using P = pair<int, bool>;
  const bool IN = false, OUT = true;
  vector<set<P>> ph(cy.size()), pv(cx.size());
  auto dual = [](set<P>& p, int i, int j) {
    auto l = p.lower_bound({i, IN});
    auto h = p.upper_bound({j, OUT});
    if(l != h) return true;
    if(h == p.end()) return false;
    if(h->second == OUT) return true;
    return false;
  };

  SegmentTree sh(cx.size()), sv(cy.size());
  for(int i = 0; i < N; ++i) {
    if(px[i] == qx[i]) {
      if(sh.find(px[i], px[i], py[i], qy[i]) || dual(pv[px[i]], py[i], qy[i])) {
        cout << 0 << endl;
        continue;
      }
      sv.update(py[i], qy[i], px[i]);
      pv[px[i]].emplace(py[i], IN);
      pv[px[i]].emplace(qy[i], OUT);
    } else {
      if(sv.find(py[i], py[i], px[i], qx[i]) || dual(ph[py[i]], px[i], qx[i])) {
        cout << 0 << endl;
        continue;
      }
      sh.update(px[i], qx[i], py[i]);
      ph[py[i]].emplace(px[i], IN);
      ph[py[i]].emplace(qx[i], OUT);
    }
    cout << 1 << endl;
  }
}

Measured memory_bytes: 100472