#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i, N) for (int i = 0; i < (int)N; ++i)
#define all(a) (a).begin(), (a).end()
template <typename Monoid>
struct SegmentTree {
  using F = function<Monoid(Monoid, Monoid)>;

  int sz;
  vector<Monoid> seg;

  const F f;
  const Monoid M1;

  SegmentTree(int n, const F f, const Monoid &M1) : f(f), M1(M1) {
    sz = 1;
    while (sz < n) sz <<= 1;
    seg.assign(2 * sz, M1);
  }

  void set(int k, const Monoid &x) { seg[k + sz] = x; }

  void build() {
    for (int k = sz - 1; k > 0; k--) {
      seg[k] = f(seg[2 * k + 0], seg[2 * k + 1]);
    }
  }

  void update(int k, const Monoid &x) {
    k += sz;
    seg[k] = x;
    while (k >>= 1) {
      seg[k] = f(seg[2 * k + 0], seg[2 * k + 1]);
    }
  }

  Monoid query(int a, int b) {
    Monoid L = M1, R = M1;
    for (a += sz, b += sz; a < b; a >>= 1, b >>= 1) {
      if (a & 1) L = f(L, seg[a++]);
      if (b & 1) R = f(seg[--b], R);
    }
    return f(L, R);
  }

  Monoid operator[](const int &k) const { return seg[k + sz]; }

  template <typename C>
  int find_subtree(int a, const C &check, Monoid &M, bool type) {
    while (a < sz) {
      Monoid nxt = type ? f(seg[2 * a + type], M) : f(M, seg[2 * a + type]);
      if (check(nxt))
        a = 2 * a + type;
      else
        M = nxt, a = 2 * a + 1 - type;
    }
    return a - sz;
  }

  template <typename C>
  int find_first(int a, const C &check) {
    Monoid L = M1;
    if (a <= 0) {
      if (check(f(L, seg[1]))) return find_subtree(1, check, L, false);
      return -1;
    }
    int b = sz;
    for (a += sz, b += sz; a < b; a >>= 1, b >>= 1) {
      if (a & 1) {
        Monoid nxt = f(L, seg[a]);
        if (check(nxt)) return find_subtree(a, check, L, false);
        L = nxt;
        ++a;
      }
    }
    return -1;
  }

  template <typename C>
  int find_last(int b, const C &check) {
    Monoid R = M1;
    if (b >= sz) {
      if (check(f(seg[1], R))) return find_subtree(1, check, R, true);
      return -1;
    }
    int a = sz;
    for (b += sz; a < b; a >>= 1, b >>= 1) {
      if (b & 1) {
        Monoid nxt = f(seg[--b], R);
        if (check(nxt)) return find_subtree(b, check, R, true);
        R = nxt;
      }
    }
    return -1;
  }
};

int Q;

struct Query {
  int type, a, b;
};

int main() {
  cin >> Q;

  vector<Query> qs(Q);
  vector<int> vals;
  rep(i, Q) {
    cin >> qs[i].type;
    if (qs[i].type == 2) continue;
    cin >> qs[i].a >> qs[i].b;
    vals.push_back(qs[i].a);
  }
  sort(all(vals));
  vals.erase(unique(all(vals)), vals.end());

  SegmentTree<ll> segC(
      vals.size() + 1, [](ll a, ll b) { return a + b; }, 0),
      segV(
          vals.size() + 1, [](ll a, ll b) { return a + b; }, 0);

  int n = 0;
  ll offset = 0;
  rep(i, Q) {
    if (qs[i].type == 1) {
      int j = distance(vals.begin(), lower_bound(all(vals), qs[i].a));
      segC.update(j, segC[j] + 1);
      segV.update(j, segV[j] + qs[i].a);
      ++n;
      offset += qs[i].b;
    } else {
      int j = segC.find_first(0, [&](ll v) { return v >= (n + 1) / 2; });
      int x = vals[j];
      ll y = offset;
      y += x * segC.query(0, j) - segV.query(0, j);
      y += -x * segC.query(j, vals.size() + 1) + segV.query(j, vals.size() + 1);
      cout << x << " " << y << endl;
    }
  }

  return 0;
}


Measured memory_bytes: 9592