#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
#define int ll

#define REP(i,n) for(int i=0;i<n;++i)
#define ALL(name) name.begin(),name.end()
#define SORT(name) sort(name.begin(), name.end())
#define ZERO(p) memset(p, 0, sizeof(p))
#define MINUS(p) memset(p, -1, sizeof(p))

const ll LLINF = (1LL<<60);
const int INF = (1LL<<30);
const double DINF = std::numeric_limits<double>::infinity();
const int MOD = 1000000007;
#define MAX_N 100010

// 配列 [0, N) について、ある範囲 [lb, ub) のうち
// まだ利用していない要素があるなら、その要素のうち
// 一番インデックスが小さいものを返す
// 愚直に実装すると O(N) だが、このクラスなら O(log N) で発見できる
class UsedChecker {
    private:
        class BITreeImpl {
            public:
                BITreeImpl() {}
                BITreeImpl(int n) { Init(n); }
                void Init(int n) {
                    m_N = n + 1;
                    m_Tree.assign(m_N, 0);
                }
                int Sum(int i) {
                    int s = 0;
                    while(i > 0) { s += m_Tree[i]; i -= i & -i; }
                    return s;
                }
                int Sum(int i, int j) { return Sum(j) - Sum(i-1); }
                void Add(int i, int x){ while(i < m_N) { m_Tree[i] += x; i += i & -i; } }
            private:
                int m_N;
                vector<int> m_Tree;
        };

    public:
        UsedChecker(){}
        UsedChecker(int n) { Init(n); }
        void Init(int n) {
            bitree.Init(n);
            for(int i = 1; i <= n; ++i) { bitree.Add(i, 1); }
        }

        // [lb, ub] 内のまだ使われていない要素で
        // 一番インデックスが小さいものを返す
        // ない場合は -1 を返す
        // O(log log N)
        int GetUnUsed(int lb, int ub) {
            if(lb > ub) { return -1; }
            if(bitree.Sum(lb+1, ub+1) <= 0) { return -1; }
            while(ub - lb > 1) {
                int mid = (lb + ub) / 2;
                if(bitree.Sum(lb+1, mid+1) > 0) { ub = mid; }
                else { lb = mid; }
            }
            if(bitree.Sum(lb+1, lb+1) > 0) { return lb; }
            return ub;
        }

        // インデックス ind を使用済みとしてマークします
        // O(log N)
        void SetToUsed(int ind) {
            int val = bitree.Sum(ind+1, ind+1);
            assert(val == 0 || val == 1);
            if(val == 1) { bitree.Add(ind+1, -1); }
        }

        // インデックス ind を未使用としてマークします
        // O(log N)
        void SetToUnUsed(int ind) {
            int val = bitree.Sum(ind+1, ind+1);
            assert(val == 0 || val == 1);
            if(val == 0) { bitree.Add(ind+1, 1); }
        }

    private:
        BITreeImpl bitree;
};


ll N, M;
vector< pair<ll, ll> > AB;  // first: スコア, second: 時間

signed main() {
    cin.tie(0); cout.tie(0);
    ios::sync_with_stdio(false);

    cin >> N >> M;
    REP(i, N) {
        ll score, day;
        cin >> day >> score;
        AB.push_back(make_pair(score, day));
    }
    SORT(AB);
    reverse(AB.begin(), AB.end());

    UsedChecker uc(M);

    ll ans = 0;
    for(int i = 0; i < N; ++i) {
        pair<ll, ll> cand = AB[i];
        // cand が入るかチェック
        int ind = uc.GetUnUsed(cand.second-1, M-1);
        if(ind >= 0) {
            uc.SetToUsed(ind);
            ans += cand.first;
        }
    }
    printf("%lld\n", ans);

    return 0;
}


Measured memory_bytes: 2672