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.Linq;
using System.Collections;
using System.Collections.Generic;
using static Library.Comfort;
using static Library.Math;
using static Library.Algorithm;
using static System.Math;

namespace AtCoderer
{
    public class App
    {
        public static void Solve()
        {
            int n, m;
            Parse(out n, out m);
            int[] a = new int[n];
            int[] b = new int[n];
            PriorityQueue<int>[] q = new PriorityQueue<int>[100005];
            for (int i = 0; i < 100005; i++)
                q[i] = new PriorityQueue<int>();
            for (int i = 0; i < n; i++)
            {
                int v, w;
                Parse(out v, out w);
                q[v-1].Push(w);
            }
            int sum = 0;
            PriorityQueue<int> p = new PriorityQueue<int>();
            for (int i = 0; i < m; i++)
            {
                while (q[i].Count != 0)
                {
                    p.Push(q[i].Pop());
                }
                if (p.Count != 0)
                {
                    sum += p.Pop();
                }
            }
            cout = sum;
        }
        public static void Main(string[] args)
        {
#if DEBUG
            while (true)
            {
                Solve();
            }
#else
            Solve();
#endif
        }
    }
}
namespace Library
{
    public static class Comfort
    {
        public const int mod = 1000000007;
        public class Point
        {
            public int a;
            public int b;
            public Point(int a, int b)
            {
                this.a = a;
                this.b = b;
            }
        }
        public static void DWrite<T>(T o)
        {
#if DEBUG
            Console.WriteLine(o);
#endif
        }
        public static int[] OrderBy(this int[] IArr)
        {
            int[] arr = new int[IArr.Length];
            Array.Copy(IArr, arr, IArr.Length);
            Array.Sort(arr);
            return arr;
        }
        public static int Max(params int[] p) => p.Max();
        public static long Max(params long[] p) => p.Max();
        public static int Min(params int[] p) => p.Min();
        public static long Min(params long[] p) => p.Min();
        public static int In()
        {
            return int.Parse(Console.ReadLine());
        }
        public static int Inl()
        {
            return int.Parse(Console.ReadLine());
        }
        public static int[] Parse()
        {
            return Console.ReadLine().Split().Select(v => int.Parse(v)).ToArray();
        }
        public static long[] Parsel()
        {
            return Console.ReadLine().Split().Select(v => long.Parse(v)).ToArray();
        }
        public static void Parse(out int a, out int b)
        {
            var r = Console.ReadLine().Split().Select(v => int.Parse(v)).ToArray();
            a = r[0];
            b = r[1];
        }
        public static void Parse(out int a, out int b, out int c)
        {
            var r = Console.ReadLine().Split().Select(v => int.Parse(v)).ToArray();
            a = r[0];
            b = r[1];
            c = r[2];
        }
        public static void Parse(out int a, out int b, out int c, out int d)
        {
            var r = Console.ReadLine().Split().Select(v => int.Parse(v)).ToArray();
            a = r[0];
            b = r[1];
            c = r[2];
            d = r[3];
        }
        public static void Parse(out long a, out long b)
        {
            var r = Console.ReadLine().Split().Select(v => long.Parse(v)).ToArray();
            a = r[0];
            b = r[1];
        }
        public static void Parse(out long a, out long b, out long c)
        {
            var r = Console.ReadLine().Split().Select(v => long.Parse(v)).ToArray();
            a = r[0];
            b = r[1];
            c = r[2];
        }
        public static void Parse(out long a, out long b, out long c, out long d)
        {
            var r = Console.ReadLine().Split().Select(v => long.Parse(v)).ToArray();
            a = r[0];
            b = r[1];
            c = r[2];
            d = r[3];
        }
        public static string ToString(this IEnumerable<char> v)
        {
            return string.Join("", v);
        }
        public static string Join<T>(this IEnumerable<T> v)
        {
            return string.Join(" ", v);
        }
        public static string Join<T>(this IEnumerable<T> v, char c)
        {
            return string.Join(c.ToString(), v);
        }
        public static string Join<T>(this IEnumerable<T> v, string s)
        {
            return string.Join(s, v);
        }
        public static object cout
        {
            set
            {
                Console.WriteLine(value);
            }
        }
        public static object dout
        {
            set
            {
                DWrite(value);
            }
        }
    }
    public static class Math
    {
        public static bool IsNatural(this float v) => v - (int)v == 0;
        public static bool IsNatural(this double v) => v - (int)v == 0;
        public static long nCm(long n, long m)
        {
            if (m == 0) return 1;
            if (n == 0) return 0;
            return n * nCm(n - 1, m - 1) / m;
        }
        public static IEnumerable<int> Factor(int n)
        {
            int i = 2;
            int tmp = n;

            while (i * i <= n)
            {
                if (tmp % i == 0)
                {
                    tmp /= i;
                    yield return i;
                }
                else
                {
                    i++;
                }
            }
            if (tmp != 1) yield return tmp;
        }
        public static int Gcd(int a, int b) => a > b ? GcdRecursive(a, b) : GcdRecursive(b, a);
        private static int GcdRecursive(int x, int y) => y == 0 ? x : GcdRecursive(y, x % y);
        public static long Gcd(long a, long b) => a > b ? GcdRecursive(a, b) : GcdRecursive(b, a);
        private static long GcdRecursive(long x, long y) => y == 0 ? x : GcdRecursive(y, x % y);
        public static long Lcm(int a, int b) => ((long)a) * b / Gcd(a, b);
    }
    public static class Algorithm
    {
        public class EnumAll
        {
            bool Over = false;
            int UpperValue;
            int Dimension;
            public int[] Current { private set; get; }
            public EnumAll(int MaxValue, int Dimension)
            {
                this.Dimension = Dimension;
                UpperValue = MaxValue;
                Current = new int[Dimension];
                Current[0] = -1;
            }
            public bool Next()
            {
                if (Over)
                    return false;
                bool flag = false;
                for (int i = 0; i < Dimension; i++)
                {
                    if (++Current[i] >= UpperValue)
                        Current[i] = 0;
                    else
                    {
                        flag = true;
                        break;
                    }
                }
                if (!flag)
                {
                    Over = true;
                    return false;
                }
                return true;
            }
        }

        public class Graph
        {
            public int Count = -1;
            private HashSet<int>[] Joined;
            public static Graph GenerateComplete(int size)
            {
                throw new NotImplementedException();
            }
            public Graph(int size)
            {
                Joined = new HashSet<int>[size];
                for (int i = 0; i < Joined.Length; i++)
                    Joined[i] = new HashSet<int>();
                Count = size;
            }
            public int[] GetConnected(int index)
            {
                return Joined[index].ToArray();
            }
            public void AddEdge(int a, int b)
            {
                if (a == b)
                    DWrite("ループを追加することはできません A:" + a + " B:" + b);
                else
                {
                    if (!Joined[a].Add(b))
                        DWrite("多重辺を追加することはできません A:" + a + " B:" + b);
                    else
                        Joined[b].Add(a);
                }
            }
            public int[] ToTree(int Root)
            {
                var ar = new int[Count];
                for (int i = 0; i < ar.Length; i++)
                    ar[i] = -10000000;
                ar[Root] = -1;
                Queue<int> bfs = new Queue<int>();
                bfs.Enqueue(Root);
                while (bfs.Count != 0)
                {
                    var t = bfs.Dequeue();
                    foreach (var v in Joined[t])
                    {
                        bfs.Enqueue(v);
                        if (ar[v] == -10000000)
                            ar[v] = t;
                    }
                }
                return ar;
            }
        }
        public class UnionFind
        {
            private int[] Parent;
            private int GetRoot(int v)
            {
                if (Parent[v] < 0)
                    return v;
                else
                    return Parent[v] = GetRoot(Parent[v]);
            }
            public UnionFind(int size)
            {
                Parent = new int[size];
                for (int i = 0; i < size; i++)
                    Parent[i] = -1;
            }
            public bool AreGrouped(int a, int b)
            {
                return GetRoot(a) == GetRoot(b);
            }
            public void Connect(int a, int b)
            {
                a = GetRoot(a);
                b = GetRoot(b);
                if (a == b) return;
                if (Parent[b] < Parent[a])
                {
                    Parent[b] += Parent[a];
                    Parent[a] = b;
                }
                else
                {
                    Parent[a] += Parent[b];
                    Parent[b] = a;
                }
            }
            public int GetGroupSize(int a)
            {
                return -Parent[GetRoot(a)];
            }
        }
    }
}
public class PriorityQueue<T> where T : IComparable
{
    List<T> buffer = new List<T>();
    static void PushHeap(List<T> array, T elem)
    {
        int n = array.Count;
        array.Add(elem);

        while (n != 0)
        {
            int i = (n - 1) / 2;
            // 親と値を入れ替え
            if (array[n].CompareTo(array[i]) > 0)
            {
                T tmp = array[n]; array[n] = array[i]; array[i] = tmp;
            }
            n = i;
        }
    }
    static void PopHeap(List<T> array)
    {
        int n = array.Count - 1;
        array[0] = array[n];
        array.RemoveAt(array.Count - 1);

        for (int i = 0, j; (j = 2 * i + 1) < n;)
        {
            // 値の大きい方の子を選ぶ
            if ((j != n - 1) && (array[j].CompareTo(array[j + 1]) < 0))
                j++;
            // 子と値を入れ替え
            if (array[i].CompareTo(array[j]) < 0)
            {
                T tmp = array[j]; array[j] = array[i]; array[i] = tmp;
            }
            i = j;
        }
    }
    public int Count
    {
        get
        {
        	return buffer.Count;
        }
    }
    public void Push(T elem)
    {
        PushHeap(this.buffer, elem);
    }
    public T Peek()
    {
        return buffer[0];
    }

    public T Pop()
    {
        T a = buffer[0];
        PopHeap(this.buffer);
        return a;
    }
}