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.Windows;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Atcoder
{
    public class Program
    {
        static void Main(string[] args)
        {
            var r1 = ReadSplit();
            var n = r1[0].Int();
            var m = r1[1].Int();
            var l = new List<KeyValuePair<int, int>>();
            for (int i = 0; i < n; i++)
            {
                var r2 = ReadSplit();
                var a = r2[0].Int();
                var b = r2[1].Int();
                l.Add(new KeyValuePair<int, int>(a, b));
            }
            l = l.OrderByDescending(x => x.Key).ToList();
            var ans = 0L;
            var target = new PriorityQueue<int>(n);
            for (int i = 1; i <= m; i++)
            {
                for (int j = l.Count; j >= 0 ; j--)
                {
                    if (l.Count == 0) break;
                    if (l[l.Count - 1].Key == i)
                    {
                        target.Enqueue(l[l.Count - 1].Value);
                        l.RemoveAt(l.Count - 1);
                    }
                    else break;
                }
                if (target.Count <= 0) continue;
                ans += target.Dequeue();
            }
            WriteRead(ans);
        }

        class PriorityQueue<T> where T : IComparable<T>
        {
            public readonly T[] Array;
            public readonly bool Greater;
            public int Count { get; private set; } = 0;

            public PriorityQueue(int capacity, bool greater = true)
            {
                this.Array = new T[capacity];
                this.Greater = greater;
            }

            public void Enqueue(T item)
            {
                this.Array[this.Count] = item;
                this.Count += 1;
                this.UpHeap();
            }

            public T Dequeue()
            {
                // 先頭要素を末尾にして再構成
                this.Swap(0, this.Count - 1);
                this.Count -= 1;
                this.DownHeap();

                return this.Array[this.Count];
            }


            private void UpHeap()
            {
                var n = this.Count - 1;
                while (n != 0)
                {
                    // 親要素の座標
                    var parent = (n - 1) / 2;

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

            private void DownHeap()
            {
                var parent = 0;
                while (true)
                {
                    var child = 2 * parent + 1;
                    if (child > this.Count - 1) break;

                    if (child < this.Count - 1 && this.Compare(this.Array[child], this.Array[child + 1]) < 0)
                    {
                        // 左より右の子のほうが大きい値の場合、右を入れ替え対象にする
                        child += 1;
                    }

                    if (this.Compare(this.Array[parent], this.Array[child]) < 0)
                    {
                        this.Swap(parent, child);
                        parent = child;
                    }
                    else
                    {
                        break;
                    }
                }
            }

            //aとbを比較する
            private int Compare(T a, T b)
            {
                var c = a.CompareTo(b);
                if (!this.Greater)
                {
                    c = -c;
                }
                return c;
            }

            //aとbを入れ替える
            private void Swap(int a, int b)
            {
                var tmp = this.Array[a];
                this.Array[a] = this.Array[b];
                this.Array[b] = tmp;
            }
        }



            public static string Read()
        {
            return Console.ReadLine();
        }

        public static string[] ReadSplit()
        {
            return Console.ReadLine().Split(' ');
        }

        public static void WriteRead(object str)
        {
            Console.WriteLine(str);
            Read();
        }

        public static void Write(object str)
        {
            Console.WriteLine(str);
        }

        private static bool ChangeMin<T>(ref T a, T b) where T : IComparable
        {
            if (a.CompareTo(b) > 0)
            {
                a = b;
                return true;
            }
            return false;
        }

        private static bool ChangekMax<T>(ref T a, T b) where T : IComparable
        {
            if (b.CompareTo(a) > 0)
            {
                a = b;
                return true;
            }
            return false;
        }
    }
}


public static class Extentions
{
    public static int Int(this object obj)
    {
        return int.Parse(obj.ToString());
    }

    public static long Long(this object obj)
    {
        return long.Parse(obj.ToString());
    }

    public static decimal Decimal(this object obj)
    {
        return decimal.Parse(obj.ToString());
    }

    public static double Double(this object obj)
    {
        return double.Parse(obj.ToString());
    }

    public static T2 GetValueZero<T1, T2>(this Dictionary<T1, T2> d, T1 key) where T2 : struct
    {
        T2 value;
        if (d.TryGetValue(key, out value))
        {
            return value;
        }
        return new T2();
    }
}