Problem:
ワカサギ釣り大会 2

桧原湖でワカサギ釣り大会が行われました。今回はキャッチ＆リリースが推奨されているようです。

参加者番号と釣った匹数またはリリースした匹数を１つのイベントとして順番に読み込み、各イベントの直後に最も多くのワカサギを手元に獲得している参加者番号と匹数を出力するプログラムを作成してください。最も多く獲得している参加者が複数いる場合（あるいは全ての参加者が 0 匹の場合）は、その中で参加者番号が最も小さい一人を出力してください。

入力

入力は以下の形式で与えられる。

n q
a1 v1
a2 v2
:
aq vq

n (1 ≤ n ≤ 1000000) は参加者の数、q (1 ≤ q ≤ 100000)はイベントの数を表す。ai (1 ≤ ai ≤ n)   vi ( -100 ≤ vi ≤ 100) は、i 番目のイベントで参加者 ai が vi 匹獲得あるいはリリースしたことを示す。vi は正の値が獲得、負の値がリリースを示し、0 が与えられることはない。

出力

各イベントごとに、最も多くのワカサギを手元に獲得している参加者の参加者番号と匹数を１つの空白区切りで１行に出力する。

入力例1

3 5
1 4
2 5
1 3
3 6
2 7

出力例1

1 4
2 5
1 7
1 7
2 12

入力例2

3 5
1 4
2 5
2 -3
3 4
1 -1

出力例2

1 4
2 5
1 4
1 4
3 4

Solution in JAVA (judge verdict: Accepted)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Scanner;
import java.util.StringTokenizer;

public class Main {
	public static class SegTree{
		int n;
		int[] dat;
		int[] top;

		public SegTree(int n_) {
			int n = 1;
			while(n < n_){
				n *= 2;
			}
			
			this.n = n;
			dat = new int[this.n * 2 - 1];
			top = new int[this.n * 2 - 1];
			for(int i = 0; i < this.n * 2 - 1 ; i++){
				dat[i] = 0;
				top[i] = 0;
			}
		}
		
		public void update_add(int k, int a){
			k += n - 1;
			dat[k] += a;
			top[k] = k - n + 1;
			
			while(k > 0){
				k = (k - 1) / 2;
				
				if(dat[k * 2 + 1] >= dat[k * 2 + 2]){
					dat[k] = dat[k * 2 + 1];
					top[k] = top[k * 2 + 1];
				}else{
					dat[k] = dat[k * 2 + 2];
					top[k] = top[k * 2 + 2];  
				}
			}
		}
		
		public int getMax(){
			return dat[0];
		}
		
		public int getTop(){
			return top[0];
		}
		
		public int size(){
			return n;
		}
		
		public String toString(){
			return Arrays.toString(dat).replaceAll("" + Long.MIN_VALUE, "-oo");
		}
		
	}
	public static void main(String[] args) throws IOException {
		Scanner sc = new Scanner(System.in);

		final int n = sc.nextInt();
		final int q = sc.nextInt();
		
		SegTree seg = new SegTree(n);
		
		for(int i = 0; i < q; i++){
			final int a = sc.nextInt() - 1;
			final int v = sc.nextInt();
			
			seg.update_add(a, v);
			System.out.println((seg.getTop() + 1) + " " + seg.getMax());
		}
	}
	
	public static class Scanner {
		
		private BufferedReader br;
		private StringTokenizer tok;
		
		public Scanner(InputStream is) throws IOException{
			br = new BufferedReader(new InputStreamReader(is));
			getLine();
		}
		
		private void getLine() throws IOException{
			tok = new StringTokenizer(br.readLine());
		}
		
		private boolean hasNext(){
			return tok.hasMoreTokens();
		}
		
		public int nextInt() throws IOException{
			if(hasNext()){
				return Integer.parseInt(tok.nextToken());
			}else{
				getLine();
				return Integer.parseInt(tok.nextToken());
			}
		}
		
		public long nextLong() throws IOException{
			if(hasNext()){
				return Long.parseLong(tok.nextToken());
			}else{
				getLine();
				return Long.parseLong(tok.nextToken());
			}
		}
		
		public double nextDouble() throws IOException{
			if(hasNext()){
				return Double.parseDouble(tok.nextToken());
			}else{
				getLine();
				return Double.parseDouble(tok.nextToken());
			}
		}
	}
}