#include <bits/stdc++.h>
using namespace std;
struct Query {
  Query(int _t = 0, int _c = 0, int _b = 0, int _s = 0)
      : type(_t), cnt(_c), b(_b), s(_s) {}
  int type;
  int cnt;
  int b;
  int s;
};
class DisjointSet {
 public:
  DisjointSet(int n)
      : N(n), parents(n, 0), ranks(n, 0), lefts(n, 0), rights(n, 0) {
    iota(parents.begin(), parents.end(), 0);
  }
  void setLeft(int x, int l) { lefts[find(x)] = l; }
  void setRight(int x, int r) { rights[find(x)] = r; }
  int getLeft(int x) { return lefts[find(x)]; }
  int getRight(int x) { return rights[find(x)]; }
  int find(int x) {
    return x == parents[x] ? x : (parents[x] = find(parents[x]));
  }
  bool merge(int x, int y) {
    x = find(x);
    y = find(y);
    if (x == y) {
      return false;
    }
    if (ranks[x] > ranks[y]) {
      swap(x, y);
    }
    if (ranks[x] == ranks[y]) {
      ++ranks[y];
    }
    parents[x] = y;
    lefts[y] = min(lefts[x], lefts[y]);
    rights[y] = max(rights[x], rights[y]);
    return true;
  }

 private:
  int N;
  vector<int> parents;
  vector<int> ranks;
  vector<int> lefts;
  vector<int> rights;
};
class Solution {
 public:
  vector<pair<int, long long>> answer(vector<Query>& qs, int n) {
    int m = qs.size();
    vector<pair<int, int>> que;
    que.resize(m);
    int sz = 0;
    vector<long long> sumB(m + 1, 0);
    vector<long long> sumS(m + 1, 0);
    for (int i = 0; i < m; ++i) {
      sumB[i + 1] = sumB[i] + qs[i].b;
      sumS[i + 1] = sumS[i] + qs[i].s;
    }
    DisjointSet ds(m + 100);
    int N = n;
    pair<int, long long> lastAns{n == 0 ? 0 : 1, 0};
    int initId = 0;
    que[sz++] = make_pair(0, initId);
    ds.setLeft(initId, -1);
    ds.setRight(initId, 1);
    vector<vector<int>> rms(m + 1);
    auto calc = [&](int i, int l, int r) -> long long {
      if (l > r) {
        return 0;
      }
      long long b = sumB[r + 1] - sumB[l];
      long long s = sumS[r + 1] - sumS[l];
      return b + i * s;
    };
    auto query = [&](int pos, int idx) -> pair<int, long long> {
      assert(sz > pos && pos >= 0);
      pos = que[pos].second;
      pos = ds.getLeft(pos) + 1;
      auto p = que[pos];
      int i = p.first;
      int l = p.second;
      int r = idx;
      return {i + 1, calc(i, l, r)};
    };
    auto promote = [&](long long diff, int num, int idx) -> int {
      int l = idx, r = m;
      while (l < r) {
        int mi = l + (r - l) / 2;
        long long rem = diff - num * (sumS[mi + 1] - sumS[idx]);
        if (rem <= 0) {
          r = mi;
        } else {
          l = mi + 1;
        }
      }
      return l;
    };
    auto insertToHead = [&](int idx, int k) -> pair<int, long long> {
      N += k;
      while (sz > 0) {
        ds.merge(que[--sz].second, idx);
      }
      que[sz++] = make_pair(0, idx);
      ds.setLeft(idx, -1);
      ds.setRight(idx, 1);
      return lastAns = {N > 0 ? 1 : 0, 0};
    };
    auto appendToTail = [&](int idx, int k) -> pair<int, long long> {
      if (lastAns.second == 0) {
        N += k;
        return lastAns;
      }
      if (sz > 0) {
        int l = ds.find(que[sz - 1].second);
        ds.setLeft(idx, sz - 1);
        int time = promote(lastAns.second, N + 1 - lastAns.first, idx);
        rms[time].push_back(l);
      }
      que[sz++] = make_pair(N, idx);
      ds.setRight(idx, sz);
      lastAns = make_pair(N + 1, 0);
      N += k;
      return lastAns;
    };
    auto recalculate = [&](int idx) -> pair<int, long long> {
      for (auto p : rms[idx]) {
        int l = ds.getLeft(p);
        int cur = l + 1;
        int r = ds.getRight(p);
        if (r >= 0 && r < sz) {
          assert(cur >= 0 && cur < sz);
          long long diff = query(cur, idx).second - query(r, idx).second;
          if (diff <= 0) {
            ds.merge(que[cur].second, que[r].second);
            r = ds.find(que[sz - 1].second);
            r = ds.getLeft(r) + 1;
            if (!(r >= 0 && r < sz) || r == cur) {
              continue;
            }
            int dis = que[r].first - que[cur].first;
            diff = query(cur, idx - 1).second - query(r, idx - 1).second;
            int time = promote(diff, dis, idx);
            if (time > idx) {
              rms[time].push_back(p);
            } else if (time == idx) {
              ds.merge(que[cur].second, que[sz - 1].second);
            }
          }
        }
      }
      return lastAns = query(sz - 1, idx);
    };
    vector<pair<int, long long>> res;
    res.reserve(m);
    for (int i = 0; i < m; ++i) {
      if (qs[i].type == 1) {
        res.emplace_back(insertToHead(i, qs[i].cnt));
      } else if (qs[i].type == 2) {
        res.emplace_back(appendToTail(i, qs[i].cnt));
      } else {
        res.emplace_back(recalculate(i));
      }
    }
    return res;
  }
};
int main(int argc, char** argv) {
  ios::sync_with_stdio(false);
  cin.tie(0);
  Solution sol;
  int n, m;
  cin >> n >> m;
  vector<Query> qs;
  qs.reserve(m);
  for (int i = 0; i < m; ++i) {
    int t = 0, c = 0, b = 0, s = 0;
    cin >> t;
    if (t == 3) {
      cin >> b >> s;
    } else {
      cin >> c;
    }
    qs.emplace_back(t, c, b, s);
  }
  auto res = sol.answer(qs, n);
  for (auto r : res) {
    cout << r.first << " " << r.second << "\n";
  }
  return 0;
}
