Problem: Serge, the chef of the famous restaurant "Salt, Pepper & Garlic" is trying to obtain his first Michelin star. He has been informed that a secret expert plans to visit his restaurant this evening.

Even though the expert's name hasn't been disclosed, Serge is certain he knows which dish from the menu will be ordered as well as what the taste preferences of the expert are. Namely, the expert requires an extremely precise proportion of salt, pepper and garlic powder in his dish.

Serge keeps a set of bottles with mixtures of salt, pepper and garlic powder on a special shelf in the kitchen. For each bottle, he knows the exact amount of each of the ingredients in kilograms. Serge can combine any number of bottled mixtures (or just use one of them directly) to get a mixture of particular proportions needed for a certain dish.

Luckily, the absolute amount of a mixture that needs to be added to a dish is so small that you can assume that the amounts in the bottles will always be sufficient. However, the numeric values describing the proportions may be quite large.

Serge would like to know whether it is possible to obtain the expert's favourite mixture from the available bottles, and if so—what is the smallest possible number of bottles needed to achieve that.

Furthermore, the set of bottles on the shelf may change over time as Serge receives new ones or lends his to other chefs. So he would like to answer this question after each such change.

For example, assume that expert's favorite mixture is 1:1:1 and there are three bottles of mixtures on the shelf:

$$$ \begin{array}{cccc} \hline Mixture & Salt & Pepper & Garlic powder \\\ \hline 1 & 10 & 20 & 30 \\\ 2 & 300 & 200 & 100 \\\ 3 & 12 & 15 & 27 \\\ \hline \end{array} $$$ Amount of ingredient in the bottle, kg 

To obtain the desired mixture it is enough to use an equivalent amount of mixtures from bottles 1 and 2. If bottle 2 is removed, then it is no longer possible to obtain it.

Write a program that helps Serge to solve this task!

Input

The first row contains three non-negative integers S_f, P_f and G_f (0 ≤ S_f, P_f, G_f; 0 < S_f+P_f+G_f ≤ 10^6) describing the amount of salt, pepper and garlic powder in the expert's favourite mixture. For any real α>0, (α{S_f}, α{P_f}, α{G_f}) also is an expert's favourite mixture.

In the second row, there is a positive integer N (number of changes on the shelf, N ≤ 100 000). You should assume that initially the shelf is empty.

Each of the next N rows describes a single change on the shelf: 

  * If a new bottle is added, the row contains capital letter A followed by three non-negative integers S_i, P_i and G_i (0 ≤ S_i, P_i, G_i; 0 < S_i+P_i+G_i ≤ 10^6) describing the amount of salt, pepper and garlic powder in the added bottle. Added bottles are numbered consecutively by unique integers starting from 1, that is, the i-th bottle corresponds to the i-th added bottle in the input data. 
  * If a particular bottle is removed from the shelf, the row contains capital letter R followed by the integer—the bottle number r_i. All values r_i in the removals are unique, r_i never exceeds total number of bottles added thus far. 

Output

Output N rows. The j-th row (1 ≤ j ≤ N) should contain the number x_j, the smallest number of bottles needed to prepare a mixture with the expert's favourite proportions of salt, pepper and garlic powder using the bottles available after the first j changes on the shelf, or 0 if it is not possible.

Scoring

Subtasks: 

  1. (13 points) N ≤ 50, 0 < S_i+P_i+G_i ≤ 10^2 
  2. (17 points) N ≤ 500, 0 < S_i+P_i+G_i ≤ 10^3 
  3. (30 points) N ≤ 5000, 0 < S_i+P_i+G_i ≤ 10^4 
  4. (40 points) No further constraints 

Example

Input


1 2 3
6
A 5 6 7
A 3 10 17
R 1
A 15 18 21
A 5 10 15
R 3


Output


0
2
0
2
1
1

Note

Pay attention that in the example, bottles 1 and 3 contain the same proportions of salt, pepper and garlic powder.

Solution (in CPP):

Solution:
#include <bits/stdc++.h>
using namespace std;
using namespace rel_ops;
struct Vector {
  long long x, y, z;
  Vector(long long x_, long long y_, long long z_) : x(x_), y(y_), z(z_) {}
};
bool operator<(const Vector& l, const Vector& r) {
  return make_tuple(l.x, l.y, l.z) < make_tuple(r.x, r.y, r.z);
}
bool operator==(const Vector& l, const Vector& r) {
  return make_tuple(l.x, l.y, l.z) == make_tuple(r.x, r.y, r.z);
}
inline long long absll(long long a) { return a < 0 ? -a : a; }
long long GCD(long long a, long long b) {
  a = absll(a);
  b = absll(b);
  if (!a || !b) return a + b;
  while (b) {
    a %= b;
    swap(a, b);
  }
  return a;
}
Vector& Norm(Vector& a) {
  if (a.x == 0) {
    if (a.y == 0)
      a.z = absll(a.z);
    else if (a.y < 0) {
      a.y *= -1;
      a.z *= -1;
    }
  } else if (a.x < 0) {
    a.x *= -1;
    a.y *= -1;
    a.z *= -1;
  }
  long long g = GCD(a.x, GCD(a.y, a.z));
  if (g) {
    a.x /= g;
    a.y /= g;
    a.z /= g;
  }
  return a;
}
inline istream& operator>>(istream& in, Vector& a) {
  long long x, y, z;
  cin >> x >> y >> z;
  a = Vector(x, y, z);
  return in;
}
inline Vector Cross(const Vector& a, const Vector& b) {
  Vector r(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x);
  long long g = GCD(r.x, GCD(r.y, r.z));
  if (g) {
    r.x /= g;
    r.y /= g;
    r.z /= g;
  }
  return r;
}
struct Frac {
  long long a, b;
  Frac(long long a_, long long b_) : a(a_), b(b_) {}
  bool operator<(Frac r) const {
    if ((b < 0) ^ (r.b < 0)) {
      r.a *= -1;
      r.b *= -1;
    }
    return a * r.b < r.a * b;
  }
  Frac operator/(const Frac& r) const { return Frac(a * r.b, b * r.a); }
  Frac operator*(const Frac& r) const { return Frac(a * r.a, b * r.b); }
  Frac operator-() const { return Frac(-a, b); }
  Frac operator-(const Frac& r) const {
    Frac res(a * r.b - r.a * b, b * r.b);
    long long g = GCD(res.a, res.b);
    if (g) {
      res.a /= g;
      res.b /= g;
    }
    return res;
  }
  operator long double() const { return (long double)a / (long double)b; }
};
bool operator==(Frac& l, Frac& r) {
  long long g = GCD(l.a, l.b);
  if (g) {
    l.a /= g;
    l.b /= g;
  }
  g = GCD(r.a, r.b);
  if (g) {
    r.a /= g;
    r.b /= g;
  }
  return l.a == r.a && l.b == r.b;
}
ostream& operator<<(ostream& out, Frac a) { return out << a.a << "/" << a.b; }
struct Point {
  Frac x, y;
  Point(const Frac& x_, const Frac& y_) : x(x_), y(y_) {}
  bool operator==(const Point& r) const { return x == r.x && y == r.y; }
  int part() const {
    static Frac zer(0, 1);
    int px = 1, py = 1;
    if (x < zer)
      px = -1;
    else if (x == zer)
      px = 0;
    if (y < zer)
      py = -1;
    else if (y == zer)
      py = 0;
    if (px < 0) return py < 0 ? 5 : (py == 0 ? 4 : 3);
    if (px == 0) return py < 0 ? 6 : 2;
    return py < 0 ? 7 : (py == 0 ? 0 : 1);
  }
  Point operator-() const { return Point(-x, -y); }
};
struct CycComp {
  bool operator()(Point l, Point r) const {
    if (l == r) return false;
    int lp = l.part(), rp = r.part();
    if (lp != rp) return lp < rp;
    if (l.x == Frac(0, 1) && r.x == Frac(0, 1)) return false;
    if (l.y == Frac(0, 1) && r.y == Frac(0, 1)) return false;
    return l.y / (long double)l.x < r.y / (long double)r.x;
  }
};
bool Near(const Point& a, const Point& b) {
  if (a.x * b.y == a.y * b.x) return true;
  if (CycComp()(a, b)) {
    int negapart = (-a).part(), bpart = b.part();
    for (int i = a.part(); i != negapart; i = (i + 1) % 8)
      if (bpart == i) return true;
    if (negapart == bpart) return CycComp()(b, -a);
    return false;
  }
  return !Near(b, a);
}
Point PointInHull(const Vector& target, const Vector& a) {
  long long asum = a.x + a.y + a.z;
  long long tsum = target.x + target.y + target.z;
  return Point(Frac(a.x, asum) - Frac(target.x, tsum),
               Frac(a.y, asum) - Frac(target.y, tsum));
}
long double triangle_area_2(long double x1, long double y1, long double x2,
                            long double y2, long double x3, long double y3) {
  return absll((x2 - x1) * (y3 - y1) - (y2 - y1) * (x3 - x1));
}
long double Area(Point a, Point b, Point c) {
  return triangle_area_2(a.x, a.y, b.x, b.y, c.x, c.y);
}
int Brutos(Vector target, const multiset<Point, CycComp>& hull) {
  if (hull.size() < 3) return 0;
  for (auto it1 = hull.begin(); it1 != hull.end() && next(it1) != hull.end();
       ++it1)
    if (!Near(*it1, *next(it1))) return 0;
  if (!Near(*hull.rbegin(), *hull.begin())) return 0;
  Point a = *hull.rbegin(), b = *hull.begin();
  if (!CycComp()(a, b) && !CycComp()(b, a)) return 0;
  return 3;
  for (auto it1 = hull.begin(); it1 != hull.end() && next(it1) != hull.end();
       ++it1) {
    Point p = *it1;
    for (auto it2 = next(it1); it2 != hull.end() && next(it2) != hull.end();
         ++it2) {
      Point q = *it2;
      if (!CycComp()(p, q) && !CycComp()(q, p)) continue;
      if (!CycComp()(p, q)) throw;
      for (auto it3 = next(it2); it3 != hull.end(); ++it3) {
        Point r = *it3;
        if (!CycComp()(p, r) && !CycComp()(r, p)) continue;
        if (!CycComp()(q, r) && !CycComp()(r, q)) continue;
        if (!CycComp()(q, r)) throw;
        Point zer(Frac(0, 1), Frac(0, 1));
        const long double eps = 0.000001L;
        long double s1 = Area(zer, p, q) + Area(zer, q, r) + Area(zer, r, p);
        long double s2 = Area(p, q, r);
        long double delta = absll(s2 - s1);
        if (!Near(p, q)) continue;
        if (!Near(q, r)) continue;
        if (!Near(r, p)) continue;
        if (delta < eps) return 3;
      }
    }
  }
  return 0;
}
int main() {
  ios::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  Vector target(0, 0, 0);
  cin >> target;
  Norm(target);
  int n;
  cin >> n;
  vector<Vector> a;
  a.reserve(n);
  multiset<Vector> b;
  map<Vector, pair<int, int>> c;
  multiset<Point, CycComp> hull;
  int gaps = 0;
  int anscnt = 0;
  while (n--) {
    char type;
    cin >> type;
    if (type == 'A') {
      Vector r(0, 0, 0);
      cin >> r;
      Norm(r);
      a.push_back(r);
      b.insert(r);
      Vector q = Cross(r, target);
      Vector qq = q;
      Norm(qq);
      if (q == qq) {
        if (++c[qq].first == 1 && c[qq].second) ++anscnt;
      } else {
        if (++c[qq].second == 1 && c[qq].first) ++anscnt;
      }
      Point point = PointInHull(target, r);
      if (point.x != Frac(0, 1) || point.y != Frac(0, 1)) {
        auto it = hull.insert(point);
        if (hull.size() > 1) {
          auto prv = (it == hull.begin() ? prev(hull.end()) : prev(it));
          auto nxt = (next(it) == hull.end() ? hull.begin() : next(it));
          if (!Near(*prv, *nxt)) --gaps;
          if (!Near(*prv, *it)) ++gaps;
          if (!Near(*it, *nxt)) ++gaps;
        }
      }
    } else {
      int j;
      cin >> j;
      --j;
      Vector r = a[j];
      b.erase(b.find(r));
      Vector q = Cross(r, target);
      Vector qq = q;
      Norm(qq);
      if (q == qq) {
        if (--c[qq].first == 0 && c[qq].second) --anscnt;
      } else {
        if (--c[qq].second == 0 && c[qq].first) --anscnt;
      }
      Point point = PointInHull(target, r);
      if (point.x != Frac(0, 1) || point.y != Frac(0, 1)) {
        auto it = hull.find(point);
        if (hull.size() > 1) {
          auto prv = (it == hull.begin() ? prev(hull.end()) : prev(it));
          auto nxt = (next(it) == hull.end() ? hull.begin() : next(it));
          if (!Near(*prv, *nxt)) ++gaps;
          if (!Near(*prv, *it)) --gaps;
          if (!Near(*it, *nxt)) --gaps;
        }
        hull.erase(it);
      }
    }
    int ans = -1;
    if (b.find(target) != b.end())
      cout << "1\n";
    else if (anscnt)
      cout << "2\n";
    else if (b.size() < 3 || gaps)
      cout << "0\n";
    else if (hull.size()) {
      Point p = *hull.rbegin(), q = *hull.begin();
      if (!CycComp()(p, q) && !CycComp()(q, p))
        cout << "0\n";
      else
        cout << "3\n";
    } else
      cout << "3\n";
  }
  cin >> n;
}