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.IO;
using System.Text;
using static System.Math;
using static System.Array;

namespace AtCoderSolve
{
    class Solve
    {
        //constant numbers
        const int mod = 1000000007;
        const int INF = int.MaxValue;
        const long SINF = long.MaxValue;

        //static variables
        static int N, M;
        //static long[] A, B;
        static List<Tuple<int, long>> ab = new List<Tuple<int, long>>();
        //input
        public static void Input()
        {
            var cin = new Scanner();
            var input = cin.SplitReader();
            N = input[0];
            M = input[1];
            for(var i = 0; i < N; i++)
            {
                var p = cin.SplitReader();
                ab.Add(new Tuple<int, long>(p[0], p[1]));
            }
            
        }

        //solve
        static void Main(string[] args)
        {
            Input();
            //var sw = new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false };
            //Console.SetOut(sw);

            ab.Sort((x, y) => (y.Item1 - x.Item1));

            var Q = new PriorityQueue<long>();
            long ans = 0;
            
            for(var i = 1; i <= M; i++)
            {
                while (ab.Count() > 0) 
                {
                    if (ab[ab.Count() - 1].Item1 <= i)
                    {
                        Q.Enqueue(ab[ab.Count() - 1].Item2);
                        ab.RemoveAt(ab.Count() - 1);
                    }
                    else
                    {
                        break;
                    }
                }

                if (Q.CountItem() > 0)
                {
                    ans += Q.Dequeue();
                }
            }

            Console.WriteLine(ans);

            //Console.Out.Flush();
        }
    }

    public class Scanner
    {
        public int[] SplitReader()
        {
            int[] array = Console.ReadLine().Split().Select(int.Parse).ToArray();
            return array;
        }
        public long[] SplitReaderL()
        {
            long[] array = Console.ReadLine().Split().Select(long.Parse).ToArray();
            return array;
        }
    }

    public class PriorityQueue<T> where T : IComparable<T>
    {
        //最大値が取り出されるQueue
        //本体
        private List<T> Q;

        public PriorityQueue()
        {
            Q = new List<T>();
        }
        public PriorityQueue(int maxsize)
        {
            Q = new List<T>(maxsize);
        }

        //Heap
        private void PushHeap(List<T> list, T item)
        {
            int n = list.Count();
            list.Add(item);

            while (n != 0)
            {
                int pIndex = (n - 1) / 2;

                if (list[n].CompareTo(list[pIndex]) > 0)
                {
                    Swap(Q, n, pIndex);
                }
                else { break; }

                n = pIndex;
            }
        }

        private void PopHeap(List<T> list)
        {
            int n = list.Count() - 1;
            list[0] = list[n];
            list.RemoveAt(n);

            int cur = 0;
            int comp;

            while (2 * cur + 1 <= n - 1)
            {
                int c1 = 2 * cur + 1;
                int c2 = 2 * (cur + 1);
                if (c1 == n - 1)
                {
                    comp = c1;
                }
                else
                {

                    comp = list[c1].CompareTo(list[c2]) > 0 ? c1 : c2;
                }

                if (list[cur].CompareTo(list[comp]) < 0)
                {
                    Swap(Q, cur, comp);
                }
                else { break; }

                cur = comp;
            }
        }

        private void Swap(List<T> list, int a, int b)
        {
            T keep = list[a];
            list[a] = list[b];
            list[b] = keep;
        }


        //実際に使う部分
        public void Enqueue(T value)
        {
            PushHeap(Q, value);
        }

        public T Dequeue()
        {
            T ret = Q[0];
            PopHeap(Q);
            return ret;
        }

        public T Peek()
        {
            return Q[0];
        }

        public int CountItem()
        {
            return Q.Count();
        }
    }

}