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 (GCC 5.4.1) (judge verdict: Time Limit Exceeded)

#include <stdio.h>
#include <string.h>
#include <stdbool.h>

void swap (int *x, int *y);
int partition (int array[], int left, int right, int array2[]);
void quick_sort (int array[], int left, int right, int array2[]);

int main(void){
  int i,j;
  int index;
  int max;
  int rest;
  int n,m;
  long long ans=0;

  scanf("%d %d", &n, &m);
  int a[n], b[n];
  bool done[n];

  memset(done, false, sizeof(done));

  for(i=0; i<n; i++){
    scanf("%d %d", &a[i], &b[i]);
  }

  quick_sort(a, 0, n-1, b);

  // printf("\n");
  // for(i=0; i<n; i++){
  //   printf("%d %d\n", a[i], b[i]);
  // }

  //M日目から逆算する
  for(i=m-1; i>=0; i--){
    rest=m-i;
    //rest日後までできる中で最大のやつを選ぶ
    max=0;
    index=-1;
    for(j=0; j<n; j++){
      if(a[j]>rest){
        break;
      }
      if(done[j]) continue;
      if(max<b[j]){
        max=b[j];
        index=j;
      }
    }
    if(index>=0){
      done[index]=true;
    }

    // if(index>=0){
    //   printf("day=%d rest=%d index=%d, a[%d]=%d, b[%d]=%d\n",i,rest,index,index,a[index],index,b[index]);
    // }else{
    //   printf("day=%d rest=%d\n",i,rest);
    // }
    ans+=max;
  }

  printf("%lld\n", ans);

  return 0;
}

/* 値を入れ替える関数 */
void swap (int *x, int *y) {
  int temp;    // 値を一時保存する変数

  temp = *x;
  *x = *y;
  *y = temp;
}

/***
* pivotを決め、
* 全データをpivotを境目に振り分け、
* pivotの添え字を返す
***/
int partition (int array[], int left, int right, int array2[]) {
  int i, j, pivot;
  i = left;
  j = right + 1;
  pivot = left;   // 先頭要素をpivotとする

  do {
    do { i++; } while (array[i] < array[pivot]);
    do { j--; } while (array[pivot] < array[j]);
    // pivotより小さいものを左へ、大きいものを右へ
    if (i < j) {
      swap(&array[i], &array[j]);
      swap(&array2[i], &array2[j]);
    }
  } while (i < j);

  swap(&array[pivot], &array[j]);   //pivotを更新
  swap(&array2[pivot], &array2[j]);

  return j;
}

/* クイックソート */
void quick_sort (int array[], int left, int right, int array2[]) {
  int pivot;

  if (left < right) {
    pivot = partition(array, left, right, array2);
    quick_sort(array, left, pivot-1, array2);   // pivotを境に再帰的にクイックソート
    quick_sort(array, pivot+1, right, array2);
  }
}