#include <cstdio>
#include <cstdint>
#include <cassert>
#include <vector>
#include <algorithm>
#include <numeric>
#include <utility>
#include <set>
#include <map>
#include <string>
#include <tuple>
#include <functional>

template <class Tp, class BinaryOperation1, class BinaryOperation2>
class segment_tree {
public:
  using binary_operation1 = BinaryOperation1;
  using binary_operation2 = BinaryOperation2;
  using value_type = Tp;

private:
  std::vector<value_type> c;
  size_t m = 1;
  binary_operation1 op1;  // aggregate
  binary_operation2 op2;  // update
  Tp identity1;

  void init_resize(size_t n) {
    m = 2*n;
    c.resize(m);
  }

  void init_aggregate() {
    for (size_t i = m/2; i-- > 1;)
      c[i] = op1(c[i<<1], c[i<<1|1]);
  }

public:
  segment_tree(size_t n,
               binary_operation1 op1,
               binary_operation2 op2,
               Tp identity): op1(op1), op2(op2), identity1(identity) {

    init_resize(n);
    c.assign(m, identity1);
  }

  segment_tree(size_t n, const Tp& e,
               binary_operation1 op1,
               binary_operation2 op2,
               Tp identity): op1(op1), op2(op2), identity1(identity) {

    init_resize(n);
    for (size_t i = m/2; i < m; ++i) c[i] = e;
    init_aggregate();
  }

  template <class ForwardIt>
  segment_tree(ForwardIt first, ForwardIt last,
               binary_operation1 op1,
               binary_operation2 op2,
               Tp identity): op1(op1), op2(op2), identity1(identity) {

    static_assert(std::is_convertible<typename ForwardIt::value_type, Tp>::value, "");
    init_resize(std::distance(first, last));
    for (size_t i = m/2; first != last; ++i) c[i] = *first++;
    init_aggregate();
  }

  void update(size_t i, Tp x) {
    i += m/2;
    c[i] = op2(c[i], x);
    while (i > 1) {
      i >>= 1;
      c[i] = op1(c[i<<1], c[i<<1|1]);
    }
  }

  value_type aggregate(size_t l, size_t r) const {
    value_type resl = identity1;
    value_type resr = identity1;
    l += m/2;
    r += m/2;
    while (l < r) {
      if (l & 1) resl = op1(resl, c[l++]);
      if (r & 1) resr = op1(c[--r], resr);
      size_t j = __builtin_ctzll(l | r);
      l >>= j;
      r >>= j;
    }
    return op1(resl, resr);
  }

  value_type operator [](size_t k) const { return c[k+m/2]; }
};

struct query {
  int type;
  intmax_t a, b;
  query() = default;
  query(int t): type(t) {}
  query(int t, intmax_t a, intmax_t b): type(t), a(a), b(b) {}
};

int main() {
  size_t Q;
  scanf("%zu", &Q);

  std::vector<std::pair<intmax_t, size_t>> xs;
  std::vector<query> qs;
  for (size_t i = 0; i < Q; ++i) {
    int t;
    scanf("%d", &t);
    if (t == 1) {
      intmax_t a, b;
      scanf("%jd %jd", &a, &b);
      qs.emplace_back(1, a, b);
      xs.emplace_back(a, i);
    } else if (t == 2) {
      qs.emplace_back(2);
    } else {
      assert(false);
    }
  }

  size_t N = xs.size();
  std::sort(xs.begin(), xs.end());
  std::map<size_t, size_t> enc;
  std::vector<intmax_t> dec(N);
  for (size_t i = 0; i < N; ++i) {
    enc[xs[i].second] = i;
    dec[i] = xs[i].first;
  }

  auto add = [](auto x, auto y) { return x+y; };
  segment_tree<intmax_t, decltype(add), decltype(add)> sum(N, add, add, 0);
  segment_tree<size_t, decltype(add), decltype(add)> index(N, add, add, 0);

  intmax_t bs = 0;
  size_t m = 0;
  for (size_t i = 0; i < Q; ++i) {
    auto const& q = qs[i];
    if (q.type == 1) {
      bs += q.b;
      sum.update(enc[i], q.a);
      index.update(enc[i], 1);
      ++m;
    } else if (q.type == 2) {
      size_t lb = 0;
      size_t ub = N;
      size_t isu = (m+1)/2;
      while (ub-lb > 1) {
        size_t mid = (lb+ub) >> 1;
        size_t is = index.aggregate(0, mid);
        ((is < isu)? lb : ub) = mid;
      }
      intmax_t rx = dec[lb];

      intmax_t left = sum.aggregate(0, lb);
      intmax_t right = sum.aggregate(ub, N);
      intmax_t ry = bs + right - left;
      if (index.aggregate(0, N) % 2 == 0) ry -= rx;
      printf("%jd %jd\n", rx, ry);
    }
  }
}


Measured memory_bytes: 29468