Problem:
Score : 400 points

Problem Statement

There are N one-off jobs available. If you take the i-th job and complete it, you will earn the reward of B_i after A_i days from the day you do it.

You can take and complete at most one of these jobs in a day.

However, you cannot retake a job that you have already done.

Find the maximum total reward that you can earn no later than M days from today.

You can already start working today.

Constraints

All values in input are integers.

1 \leq N \leq 10^5

1 \leq M \leq 10^5

1 \leq A_i \leq 10^5

1 \leq B_i \leq 10^4

Input

Input is given from Standard Input in the following format:

N M
A_1 B_1
A_2 B_2
\vdots
A_N B_N

Output

Print the maximum total reward that you can earn no later than M days from today.

Sample Input 1

3 4
4 3
4 1
2 2

Sample Output 1

5

You can earn the total reward of 5 by taking the jobs as follows:

Take and complete the first job today. You will earn the reward of 3 after four days from today.

Take and complete the third job tomorrow. You will earn the reward of 2 after two days from tomorrow, that is, after three days from today.

Sample Input 2

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

Sample Output 2

10

Sample Input 3

1 1
2 1

Sample Output 3

0

Solution in C# (Mono 4.6.2.0) (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AtCorder
{
	public class Program
	{
		static void Main(string[] args)
		{
			Scanner cin = new Scanner();
			int n = cin.Int();
			int m = cin.Int();
			int max = 100001;
			List<long>[] map = new List<long>[max];
			for (int i = 0; i < max; i++) {
				map[i] = new List<long>();
			}

			for (int i = 0; i < n; i++) {
				int a = cin.Int();
				long b = cin.Long();
				map[a].Add(b);
			}

			long ans = 0;
			PriorityQueue<long> queue = new PriorityQueue<long>();
			for (int i = 1; i <= m; i++) {
				for (int j = 0; j < map[i].Count; j++) {
					queue.Push(map[i][j]);
				}

				if (queue.Count > 0) {
					ans += queue.Pop();
				}
			}

			Console.WriteLine(ans);
		}
	}

	class PriorityQueue<T> where T : IComparable<T>
	{
		List<T> buf;
		public bool rev = false;
		public PriorityQueue() { buf = new List<T>(); }
		int cmp(int i, int j) => buf[i].CompareTo(buf[j]) * (rev ? -1 : 1);
		void swap(int i, int j) { var t = buf[i]; buf[i] = buf[j]; buf[j] = t; }
		public void Push(T elem)
		{
			int n = buf.Count;
			buf.Add(elem);
			while (n > 0) {
				int i = (n - 1) >> 1;
				if (cmp(n, i) > 0)
					swap(i, n);
				n = i;
			}
		}
		public T Pop()
		{
			T ret = buf[0];
			int n = buf.Count - 1;
			buf[0] = buf[n];
			buf.RemoveAt(n);
			for (int i = 0, j; (j = (i << 1) + 1) < n; i = j) {
				if (j != n - 1 && cmp(j, j + 1) < 0)
					++j;
				if (cmp(i, j) < 0)
					swap(i, j);
			}
			return ret;
		}
		public T Top => buf[0];
		public int Count => buf.Count;
	}

	public class Scanner
	{
		private readonly char[] delimiter_ = new char[] { ' ' };
		private string[] buf_;
		private int index_;
		
		public Scanner()
		{
			buf_ = new string[0];
			index_ = 0;
		}

		public string Next()
		{
			if (index_ < buf_.Length) {
				return buf_[index_++];
			}

			string st = Console.ReadLine();
			while (st == "") {
				st = Console.ReadLine();
			}

			buf_ = st.Split(delimiter_, StringSplitOptions.RemoveEmptyEntries);
			if (buf_.Length == 0) {
				return Next();
			}

			index_ = 0;
			return buf_[index_++];
		}

		public int Int()
		{
			return int.Parse(Next());
		}
		public int[] ArrayInt(int N, int add = 0)
		{
			int[] Array = new int[N];
			for (int i = 0; i < N; i++) {
				Array[i] = Int() + add;
			}
			return Array;
		}

		public long Long()
		{
			return long.Parse(Next());
		}

		public long[] ArrayLong(int N, long add = 0)
		{
			long[] Array = new long[N];
			for (int i = 0; i < N; i++) {
				Array[i] = Long() + add;
			}
			return Array;
		}

		public double Double()
		{
			return double.Parse(Next());
		}

		public double[] ArrayDouble(int N, double add = 0)
		{
			double[] Array = new double[N];
			for (int i = 0; i < N; i++) {
				Array[i] = Double() + add;
			}
			return Array;
		}
	}
}