#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <stack>
#include <queue>
#include <cmath>
#include <tuple>
#include <cstdio>
#include <bitset>
#include <sstream>
#include <iterator>
#include <numeric>
#include <map>
#include <cstring>
#include <set>
#include <functional>
#include <iomanip>

using namespace std;

//#define DEBUG_ //!!提出時にコメントアウト!!
#ifdef DEBUG_
	#define dump(x)  cerr << #x << " = " << (x) << endl;
#else
	#define dump(x)  ;
#endif

#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define REP(i,n)  FOR(i,0,n)
#define SZ(x) ((int)(x).size())
#define pb push_back
#define eb emplace_back

//#define int long long

typedef long long LL;
typedef vector<int> VI;
typedef vector<LL> VL;
typedef vector<VI> VVI;
typedef vector<string> VS;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;

template <typename T>
std::string printVector(const std::vector<T> &data)
{
    std::stringstream ss;
    std::ostream_iterator<T> out_it(ss, ", ");
    ss << "[";
    std::copy(data.begin(), data.end() - 1, out_it);
    ss << data.back() << "]";
    return ss.str();
}

const int MOD = 1e9+7;
const LL LINF = 1001002003004005006ll;
const int INF = 1001001001;

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];
  }

  bool isOK(int mid, LL key) {
      if(query(0,mid+1) >= key) return true;
      else return false;
  }

  int binary_search(LL key) {
      int ng = -1; //「index = 0」が条件を満たすこともあるので、初期値は -1
      int ok = (int)seg.size(); // 「index = a.size()-1」が条件を満たさないこともあるので、初期値は a.size()
      /* どんな二分探索でもここの書き方を変えずにできる！ */
      while (abs(ng - ok) > 1) {
          int mid = (ok + ng) / 2;
          if (isOK(mid, key)) ok = mid;
          else ng = mid;
      }
      /* left は条件を満たさない最大の値、right は条件を満たす最小の値になっている */
      return ok;
  }
};

signed main(int argc, char const *argv[])
{
    cin.tie(0);
    ios::sync_with_stdio(false);
    int Q; cin >> Q;
    VI T(212345), A(212345), B(212345);
    VI as;
    REP(i,Q){
        int id; cin >> id;
        T[i] = id;
        if(id == 1){
            cin >> A[i] >> B[i];
            as.eb(A[i]);
        }
    }
    sort(as.begin(),as.end());
    as.erase(unique(as.begin(),as.end()),as.end());

    map<int,int> mp;
    int sz = as.size();
    REP(i,sz) mp[as[i]] = i;

    SegmentTree<LL> segnum(sz,
    [](LL a, LL b){
        return a+b;
    },0);

    SegmentTree<LL> segsum(sz,
    [](LL a, LL b){
        return a+b;
    },0);

    LL fix = 0;
    LL cnt = 0;

    REP(i,Q){
        if(T[i] == 1){
            int a = mp[A[i]];
            segnum.update(a,segnum[a]+1);
            segsum.update(a,segsum[a]+A[i]);
            fix += B[i];
            cnt++;
        }
        else{
            dump(fix)
            LL ans = fix;
            int idx = segnum.binary_search((cnt+1)/2);
            dump(idx)
            dump(segsum[0])
            dump(segsum[1])
            dump(segsum.query(idx+1,sz))
            ans += segsum.query(idx+1,sz);
            ans -= as[idx] * segnum.query(idx+1,sz);
            ans -= segsum.query(0,idx);
            ans += as[idx] * segnum.query(0,idx);
            cout << as[idx] << " " << ans << endl;
        }
    }

}


Measured memory_bytes: 14328