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# (.NET Core 3.1.201) (judge verdict: Accepted)

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
//自由度の高い、Mが小さい仕事を考慮するため、後ろから考える
//貪欲法(割りの良い奴を選び続ける)=>「真に良い」が必要なので、今回は使えない
//単純比較ができるように作り替えること=>ABのうちAは除く
//最大の値を出すので優先度付きキュー
namespace D
{
    class Program
    {
        static void Main(string[] args)
        {
            string[] In = Console.ReadLine().Split(' ');
            int n = int.Parse(In[0]);
            int m = int.Parse(In[1]);
            var J = new List<int>[m + 1];//それぞれの日について管理
            for(int i=0; i < m + 1; i++)
            {
                J[i] = new List<int>() { };
            }
            for(int i = 0; i < n; i++)
            {
                string[] In2 = Console.ReadLine().Split(' ');
                int a = int.Parse(In2[0]);
                int b = int.Parse(In2[1]);
                if (a > m) continue;
                J[m - a].Add(b);
            }
            var q = new PriorityQueue<int>(100000);//その日にしかできないことが最善手とは限らない
            long ans = 0;
            for(int i = m-1; i >= 0; i--)
            {
                foreach(var j in J[i])
                {
                    q.Push(j);
                }
                if(q.Count>=1) ans += q.Pop();
            }
            Console.WriteLine(ans);
        }
    }
    class PriorityQueue<T> where T : IComparable<T>
    {
        private readonly T[] _array;
        private readonly IComparer _comparer;
        public int Count { get; private set; } = 0;
        public T Root => _array[0];

        public PriorityQueue(int capacity, IComparer comparer = null)
        {
            _array = new T[capacity];
            _comparer = comparer;
        }

        /// <summary>
        /// 要素を挿入する
        /// </summary>
        public void Push(T item)
        {
            _array[this.Count] = item;
            Count += 1;

            var n = Count - 1;                  // 末尾(追加した)のノードの番号
            while (n != 0)
            {
                var parent = (n - 1) / 2;       // 親ノードの番号

                if (Compare(_array[n], _array[parent]) > 0)
                {
                    Swap(n, parent);
                    n = parent;
                }
                else
                {
                    break;
                }
            }
        }

        /// <summary>
        /// 優先度の一番高いものを取り出す
        /// </summary>
        public T Pop()
        {
            Swap(0, this.Count - 1);            // 先頭要素を末尾にする
            Count -= 1;

            var parent = 0;                     // 親ノードの番号
            while (true)
            {
                var child = 2 * parent + 1;     // 子ノードの番号
                if (child > Count - 1) break;

                // 値の大きい方の子を選ぶ
                if (child < Count - 1 && Compare(_array[child], _array[child + 1]) < 0) child += 1;

                // 子の方が親より大きければ入れ替える
                if (Compare(_array[parent], _array[child]) < 0)
                {
                    Swap(parent, child);
                    parent = child;
                }
                else
                {
                    break;
                }
            }

            return _array[Count];
        }

        /// <summary>
        /// 大きいものから列挙していく
        /// withPop = falseのときは順番関係なく取り出しもしないが素早く全要素を取得できる　
        /// </summary>
        public IEnumerable<T> GetAllElements(bool withPop = true)
        {
            int count = Count;
            for (int i = 0; i < count; i++)
            {
                if (withPop) yield return Pop();
                else yield return _array[count - i - 1];
            }
        }

        private int Compare(T a, T b)
        {
            if (_comparer == null) return a.CompareTo(b);
            return _comparer.Compare(a, b);
        }

        private void Swap(int a, int b)
        {
            var tmp = _array[a];
            _array[a] = _array[b];
            _array[b] = tmp;
        }
    }
}
//namespace D
//{
//    class Program
//    {
//        static void Main(string[] args)
//        {
//            string[] In = Console.ReadLine().Split(' ');
//            int n = int.Parse(In[0]);
//            int m = int.Parse(In[1]);
//            int[] Dp = new int[m + 1];
//            //ShowDp(Dp);
//            Dp[0] = 0;
//            for (int i = 0; i < n; i++)
//            {
//                In = Console.ReadLine().Split(' ');
//                int a = int.Parse(In[0]);
//                int b = int.Parse(In[1]);
//                for (int j = 0; j < m; j++)
//                {
//                    int mj = (int)Math.Min(j + a, m);//njは次の添え字、minは基本j+a使うが、配列外参照を防ぐためhもいれてる
//                    Dp[mj] = (int)Math.Max(Dp[mj], Dp[j] + b);
//                    //ShowDp(Dp);
//                }
//            }
//            Console.WriteLine(Dp[m]);
//        }
//        static void ShowDp(int[] Dp)
//        {
//            foreach (var d in Dp)
//            {
//                if (d == 0) Console.Write(" *");
//                else Console.Write(" " + d);
//            }
//            Console.WriteLine();
//        }
//    }
//}