#include <bits/stdc++.h>
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
using namespace std;
namespace ywy {
inline int get() {
  int n = 0;
  char c;
  while ((c = getchar()) || 23333) {
    if (c >= '0' && c <= '9') break;
    if (c == '-') goto s;
  }
  n = c - '0';
  while ((c = getchar()) || 23333) {
    if (c >= '0' && c <= '9')
      n = n * 10 + c - '0';
    else
      return (n);
  }
s:
  while ((c = getchar()) || 23333) {
    if (c >= '0' && c <= '9')
      n = n * 10 - c + '0';
    else
      return (n);
  }
}
long long data[600001], ints[600001];
int ch[600001][2], size[600001], tmp[600001], gn = 1, gptr;
typedef struct _n {
  long long pt;
  long long data;
  friend bool operator<(const _n &a, const _n &b) {
    if (a.data == b.data) return (a.pt < b.pt);
    return (a.data > b.data);
  }
  friend bool operator==(const _n &a, const _n &b) {
    return (a.pt == b.pt && a.data == b.data);
  }
} node;
unsigned char isdel[600001];
long long mx[600001], mn[600001];
inline void up(int tree) {
  mx[tree] = max(mx[ch[tree][0]], mx[ch[tree][1]]),
  mn[tree] = min(mn[ch[tree][0]], mn[ch[tree][1]]);
  if (!isdel[tree])
    mx[tree] = max(mx[tree], data[tree]), mn[tree] = min(mn[tree], data[tree]);
}
typedef struct _heap {
  priority_queue<node> me, del;
  inline int empty() {
    wh();
    return (me.empty());
  }
  inline void wh() {
    while (!me.empty() && !del.empty() && me.top() == del.top())
      me.pop(), del.pop();
  }
  inline void push(node n) { me.push(n); }
  inline node top() {
    wh();
    return (me.top());
  }
  inline void pop() {
    wh();
    me.pop();
  }
  inline void erase(node n) { del.push(n); }
} heap;
heap que;
void dfs(int pt) {
  if (!pt) return;
  dfs(ch[pt][0]);
  if (!isdel[pt]) tmp[gptr] = pt, gptr++;
  dfs(ch[pt][1]);
}
int build(int l, int r) {
  if (l > r) return (0);
  int mid = (l + r) >> 1, tree = tmp[mid];
  size[tree] = r - l + 1;
  ch[tree][0] = build(l, mid - 1);
  ch[tree][1] = build(mid + 1, r);
  up(tree);
  return (tree);
}
void insert(int &tree, int me) {
  if (!tree) {
    tree = me;
    up(tree);
    return;
  }
  size[tree]++;
  insert(ch[tree][data[me] > data[tree]], me);
  up(tree);
  if (max(size[ch[tree][0]], size[ch[tree][1]]) > (double)size[tree] * 0.66) {
    gptr = 1;
    dfs(tree);
    tree = build(1, gptr - 1);
  }
}
void del(int tree, long long dat) {
  if (data[tree] == dat) {
    isdel[tree] = 1;
    up(tree);
    return;
  }
  del(ch[tree][dat > data[tree]], dat);
  up(tree);
}
int getpre(int tree, long long pos) {
  if (!tree || mn[tree] >= pos) return (0);
  if (!isdel[tree] && data[tree] < pos) {
    int cjr = getpre(ch[tree][1], pos);
    if (cjr) return (cjr);
    return (tree);
  }
  if (data[tree] < pos) {
    int cjr = getpre(ch[tree][1], pos);
    if (cjr) return (cjr);
    return (getpre(ch[tree][0], pos));
  }
  return (getpre(ch[tree][0], pos));
}
int getnxt(int tree, long long pos) {
  if (!tree || mx[tree] <= pos) return (0);
  if (!isdel[tree] && data[tree] > pos) {
    int cjr = getnxt(ch[tree][0], pos);
    if (cjr) return (cjr);
    return (tree);
  }
  if (data[tree] > pos) {
    int cjr = getnxt(ch[tree][0], pos);
    if (cjr) return (cjr);
    return (getnxt(ch[tree][1], pos));
  }
  return (getnxt(ch[tree][1], pos));
}
int getmax(int tree) {
  if (!tree || mx[tree] < mn[tree]) return (0);
  if (!isdel[tree]) {
    int cjr = getmax(ch[tree][1]);
    if (cjr) return (cjr);
    return (tree);
  }
  int cjr = getmax(ch[tree][1]);
  if (cjr) return (cjr);
  return (getmax(ch[tree][0]));
}
inline void clear(priority_queue<node> &q) {
  priority_queue<node> tmp;
  q = tmp;
}
void print(long long num) {
  if (num >= 10) print(num / 10);
  putchar(num % 10 + '0');
}
int find(int tree, long long x) {
  if (data[tree] == x) return (tree);
  return (find(ch[tree][x > data[tree]], x));
}
void ywymain() {
  mx[0] = -0x7f7f7f7f7f7f7f7f;
  mn[0] = 0x7f7f7f7f7f7f7f7f;
  long long n = get();
  int m = get();
  int rt = gn;
  gn++;
  data[rt] = 0;
  ints[rt] = 0;
  size[rt] = 1;
  up(rt);
  long long k = 0, b = 0;
  while (m) {
    m--;
    int op = get();
    if (op == 1) {
      int dk = get();
      rt = gn;
      gn++;
      data[rt] = 0;
      ints[rt] = 0;
      size[rt] = 1;
      up(rt);
      k = 0;
      b = 0;
      n += dk;
      clear(que.me);
      clear(que.del);
    }
    if (op == 2) {
      int dk = get();
      int me = gn;
      gn++;
      data[me] = n;
      ints[me] = -n * k - b;
      int lst = getmax(rt);
      node cjr;
      cjr.pt = n;
      cjr.data = ((ints[lst] - ints[me]) / (data[me] - data[lst]) +
                  ((ints[lst] - ints[me]) % (data[me] - data[lst]) != 0));
      que.push(cjr);
      n += dk;
      insert(rt, me);
    }
    if (op == 3) {
      b += get();
      k += get();
    }
    while (!que.empty() && que.top().data <= k) {
      long long me = que.top().pt;
      que.pop();
      int pr = getpre(rt, me), nx = getnxt(rt, me);
      int m = find(rt, me);
      if (nx) {
        node cjr;
        cjr.pt = data[nx];
        cjr.data = ((ints[m] - ints[nx]) / (data[nx] - data[m]) +
                    ((ints[m] - ints[nx]) % (data[nx] - data[m]) != 0));
        que.erase(cjr);
      }
      if (pr && nx) {
        node cjr;
        cjr.pt = data[nx];
        cjr.data = ((ints[pr] - ints[nx]) / (data[nx] - data[pr]) +
                    ((ints[pr] - ints[nx]) % (data[nx] - data[pr]) != 0));
        que.push(cjr);
      }
      del(rt, me);
    }
    int me = getmax(rt);
    printf("%lld %lld\n", data[me] + 1, ints[me] + k * data[me] + b);
  }
}
}  // namespace ywy
int main() {
  ywy::ywymain();
  return (0);
}
