#include <map>
#include <set>
#include <list>
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <string>
#include <vector>
#include <complex>
#include <cstdlib>
#include <cstring>
#include <numeric>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>

#define mp       make_pair
#define pb       push_back
#define all(x)   (x).begin(),(x).end()
#define rep(i,n) for(int i=0;i<(n);i++)
#define repi(i,a,b) for(int i = (a); i < (b); i++)

using namespace std;

typedef    long long          ll;
typedef    unsigned long long ull;
typedef    vector<bool>       vb;
typedef    vector<int>        vi;
typedef    vector<vb>         vvb;
typedef    vector<vi>         vvi;
typedef    pair<int,int>      pii;

const int INF=1<<29;
const double EPS=1e-9;

const int dx[]={1,0,-1,0},dy[]={0,-1,0,1};
//segment-tree
ll n;//nは2のべき乗
pii dat[2000110*2-1];

//初期化
void init(ll _n){
	//べき乗を計算しておく
	n = 1;
	while(n <_n)
		n *=2;
  //すべての値をINT_MAXに
	for(ll i =0;i <2*n-1;i++){
		dat[i].first=-INF;
	}
}

//i番目の値(0-indexed)をxに変更
void update(ll i,ll x,ll c){
  //葉のノード番号
	i +=n-1;
	dat[i].first = x;
	dat[i].second =-c;
	while(i >0){
		i =(i-1)/2;
		if(dat[i*2+1]>dat[i*2+2]){
			dat[i]=dat[i*2+1];
		}else{
			dat[i]=dat[i*2+2];
		}
	}
}

//[a,b)の最小値,l,rにはノードkに対応づく区画を与える
//外からはquery(a,b,0,0,n)のように呼ぶ
/*int query(int a,int b,int k,int l,int r){
  if(r <=a||b <=l)//交差しない
  	return INT_MAX;
  if(a <=l&&r<=b)//完全に含む
  	return dat[k].first;
  else{
  	int vl =query(a, b, k*2+1, l, (l+r)/2);
  	int vr =query(a, b, k*2+2, (l+r)/2, r);
  	return min(vl,vr);
  }
}*/
  int main(){
  	int q;
  	cin>>n>>q;
  	init(n);
  	for(int i =0;i <q;i++){
  		ll x,y;
  		cin>>x>>y;
  		x--;
  		ll tmp =x+n-1;
  		if(dat[tmp].first!=-INF){
  			update(x,dat[tmp].first+y,x);
  		}else{
  			update(x, y, x);
  		}
  		cout <<-1*dat[0].second+1<<" "<<dat[0].first<<endl;
  	}
  	return 0;
  }