#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const long long INF = 0x3f3f3f3f3f3f3f3f;
const int maxn = 3e5 + 50;
const int mod = 1e9 + 7;
int a[maxn];
long long pre[maxn], lg[maxn << 2];
long long la[maxn << 2], lb[maxn << 2];
void build(int rt, int l, int r) {
  if (l == r)
    lg[rt] = a[l];
  else {
    int mid = (l + r) >> 1;
    build((rt << 1), l, mid);
    build((rt << 1 | 1), mid + 1, r);
    lg[rt] = lg[(rt << 1)] + lg[(rt << 1 | 1)];
  }
}
void down(int rt) {
  lb[(rt << 1)] += lb[rt];
  lb[(rt << 1 | 1)] += lb[rt];
  la[(rt << 1)] += la[rt];
  la[(rt << 1 | 1)] += la[rt] + lg[(rt << 1)] * lb[rt];
  la[rt] = lb[rt] = 0;
}
void update(int rt, int l, int r, int L, int R, long long b, int s) {
  if (L <= l and r <= R) {
    la[rt] += b;
    lb[rt] += s;
  } else {
    if (la[rt] or lb[rt]) down(rt);
    int mid = (l + r) >> 1;
    if (L <= mid and R > mid) {
      update((rt << 1), l, mid, L, mid, b, s);
      update((rt << 1 | 1), mid + 1, r, mid + 1, R,
             b + (pre[(mid)] - pre[(L - 1)]) * s, s);
    } else if (L <= mid) {
      update((rt << 1), l, mid, L, R, b, s);
    } else {
      update((rt << 1 | 1), mid + 1, r, L, R, b, s);
    }
  }
}
long long query(int rt, int l, int r, int pos) {
  if (l == r)
    return la[rt];
  else {
    if (la[rt] or lb[rt]) down(rt);
    int mid = (l + r) >> 1;
    if (pos <= mid) return query((rt << 1), l, mid, pos);
    return query((rt << 1 | 1), mid + 1, r, pos);
  }
}
int od[maxn], b[maxn], s[maxn];
deque<int> qu;
int le[maxn], ri[maxn];
int fl(int k) { return le[k] ? le[k] = fl(le[k]) : k; }
int fr(int k) { return ri[k] ? ri[k] = fr(ri[k]) : k; }
set<pair<long long, int> > use;
long long add;
pair<long long, int> my[maxn];
inline void check_merge(int r, int s, int cc) {
  if (use.empty()) {
    add -= s;
    return;
  }
  while (!use.empty()) {
    pair<long long, int> f = *use.begin();
    if (f.first + add > s) break;
    use.erase(use.begin());
    int pos = f.second;
    le[pos] = pos - 1;
    ri[pos - 1] = pos;
    int g = fr(pos);
    if (g != r) {
      ++g;
      use.erase(my[g]);
      int an = fl(g - 1);
      long long a = query(1, 1, cc, an), b = query(1, 1, cc, g),
                len = (pre[(g - 1)] - pre[(an - 1)]);
      my[g].first = (a - b + len - 1) / len - add;
      use.insert(my[g]);
    }
  }
  add -= s;
}
int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int n, m;
  cin >> n >> m;
  qu.push_back(n);
  int pos = 1;
  for (int i = 1; i <= m; ++i) {
    cin >> od[i];
    if (od[i] == 1) {
      int len;
      cin >> len;
      qu.push_front(len);
      ++pos;
    } else if (od[i] == 2) {
      int len;
      cin >> len;
      qu.push_back(len);
    } else {
      cin >> b[i] >> s[i];
    }
  }
  int cc = 0;
  for (int i = 1; !qu.empty(); ++i) {
    a[i] = qu.front();
    qu.pop_front();
    cc = i;
  }
  for (int i = 1; i <= cc; ++i) pre[i] = pre[i - 1] + a[i];
  build(1, 1, cc);
  int ul = pos, ur = pos;
  for (int i = 1; i <= m; ++i) {
    if (od[i] == 1) {
      le[ul] = ul - 1;
      ri[ul - 1] = ul;
      --ul;
      for (auto it = use.begin(); it != use.end(); ++it) {
        int pos = it->second;
        le[pos] = pos - 1;
        ri[pos - 1] = pos;
      }
      use.clear();
    } else if (od[i] == 2) {
      ++ur;
      my[ur].second = ur;
      long long val = query(1, 1, cc, fl(ur - 1));
      if (val == 0) {
        le[ur] = ur - 1;
        ri[ur - 1] = ur;
      } else {
        int r = ur;
        int an = fl(r - 1);
        long long a = query(1, 1, cc, an), b = query(1, 1, cc, r),
                  len = (pre[(r - 1)] - pre[(an - 1)]);
        my[r].first = (a - b + len - 1) / len - add;
        use.insert(my[r]);
      }
    } else {
      check_merge(ur, s[i], cc);
      update(1, 1, cc, ul, ur, b[i], s[i]);
    }
    int p = fl(ur);
    cout << (pre[(p - 1)] - pre[(ul - 1)]) + 1 << " " << query(1, 1, cc, p)
         << "\n";
  }
  return 0;
}
