Problem:
Score : 600 points

Problem Statement

Silver Fox is fighting with N monsters.

The monsters are standing in a row, and we can assume them to be standing on a number line. The i-th monster, standing at the coordinate X_i, has the health of H_i.

Silver Fox can use bombs to attack the monsters.
Using a bomb at the coordinate x decreases the healths of all monsters between the coordinates x-D and x+D (inclusive) by A.
There is no way other than bombs to decrease the monster's health.

Silver Fox wins when all the monsters' healths become 0 or below.

Find the minimum number of bombs needed to win.

Constraints

1 \leq N \leq 2 \times 10^5

0 \leq D \leq 10^9

1 \leq A \leq 10^9

0 \leq X_i \leq 10^9

1 \leq H_i \leq 10^9

X_i are distinct.

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N D A
X_1 H_1
:
X_N H_N

Output

Print the minimum number of bombs needed to win.

Sample Input 1

3 3 2
1 2
5 4
9 2

Sample Output 1

2

First, let us use a bomb at the coordinate 4 to decrease the first and second monsters' health by 2.

Then, use a bomb at the coordinate 6 to decrease the second and third monsters' health by 2.

Now, all the monsters' healths are 0.
We cannot make all the monsters' health drop to 0 or below with just one bomb.

Sample Input 2

9 4 1
1 5
2 4
3 3
4 2
5 1
6 2
7 3
8 4
9 5

Sample Output 2

5

We should use five bombs at the coordinate 5.

Sample Input 3

3 0 1
300000000 1000000000
100000000 1000000000
200000000 1000000000

Sample Output 3

3000000000

Watch out for overflow.

Solution in C++14 (GCC 5.4.1) (judge verdict: Accepted)

#include <bits/stdc++.h>

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

template<typename T1,typename T2> inline void chmin(T1 &a, T2 b){ if(a > b) a = b; }
template<typename T1,typename T2> inline void chmax(T1 &a, T2 b){ if(a < b) a = b; }

#define REP(i,n) for(int i=0;i<n;++i)
#define SORT(name) sort(name.begin(), name.end())
#define ZERO(p) memset(p, 0, sizeof(p))
#define MINUS(p) memset(p, -1, sizeof(p))
#if 0
#  define DBG(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#  define DBG(fmt, ...)
#endif

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

// 区間加算・区間更新・区間和を求める遅延セグ木
// 区間への加算、更新、和の導出が O(log N) でできる
// メモリは 3N * sizeof(ll) 消費
// 加算と更新は実装をどちらか一つにするとより高速化できる
class LazySegmentTree {
    private:
        // 遅延評価の種類を表す enum
        enum Status {
            None = 0,           // 遅延評価なし
            Update_Add = 1,     // 加算の遅延評価
            Update_Reset = 2    // 更新の遅延評価
        };

    public:
        LazySegmentTree() {}
        LazySegmentTree(ll n) { Init(n); }
        // 初期化
        // n: セグメント木で扱う配列の長さ
        void Init(ll n) {
            // 要素数を 2 べきにする
            m_Size = 1;
            while(m_Size < n) { m_Size <<= 1; }
            m_Seg.assign(2 * m_Size, 0);    // 単位元で初期化
            m_Lazy.assign(2 * m_Size, 0);
            m_LazyFlag.assign(2 * m_Size, None);
        }
        // k 番目の要素に x をセット (0-indexed)
        void Set(ll k, ll x) {
            assert(0 <= k && k < m_Size);
            m_Seg[k + m_Size] = x;
        }
        // セグ木構築 O(N)
        void Build() {
            for(int k = m_Size - 1; k > 0; k--) {
                // 子ノードに対しての演算結果を親ノードに格納
                m_Seg[k] = m_Seg[2 * k + 0] + m_Seg[2 * k + 1];
            }
        }
        // 区間 [a, b) に対して x を足します。 O(log N)
        void Add(ll a, ll b, ll x) {
            assert(0 <= a && a <= b && b <= m_Size);
            AddImpl(a, b, x, 1, 0, m_Size);
        }
        // 区間 [a, b) 全ての要素を x にします。 O(log N)
        void Reset(ll a, ll b, ll x) {
            assert(0 <= a && a <= b && b <= m_Size);
            ResetImpl(a, b, x, 1, 0, m_Size);
        }
        // 区間 [a, b) の総和を返します。 O(log N)
        ll Query(ll a, ll b) {
            assert(0 <= a && a <= b && b <= m_Size);
            return QueryImpl(a, b, 1, 0, m_Size);
        }
        // セグ木で管理している要素の k 番目にアクセスします O(log N)
        ll operator[](const ll &k) {
            assert(0 <= k && k < m_Size);
            return Query(k, k + 1);
        }

    private:
        // セグ木の k 地点からの区間遅延評価を行います
        void Propagate(ll k) {
            if(m_LazyFlag[k] == Update_Add) {
                if(k < m_Size) {
                    // 違うタイプのものがまだ伝搬していないなら更に下に伝搬させておく
                    if(m_LazyFlag[2 * k + 0] == Update_Reset) { Propagate(2 * k + 0); }
                    if(m_LazyFlag[2 * k + 1] == Update_Reset) { Propagate(2 * k + 1); }
                    // 子があるなら子の遅延配列に値を伝搬
                    // 子の範囲は親の半分なので /2 する
                    m_Lazy[2 * k + 0] += m_Lazy[k] / 2;
                    m_Lazy[2 * k + 1] += m_Lazy[k] / 2;
                    m_LazyFlag[2 * k + 0] = m_LazyFlag[2 * k + 1] = Update_Add;
                }
                m_Seg[k] += m_Lazy[k];  // 遅延評価ぶんの反映
                m_Lazy[k] = 0;          // 反映後クリア
                m_LazyFlag[k] = None;
            }
            else if(m_LazyFlag[k] == Update_Reset) {
                if(k < m_Size) {
                    m_Lazy[2 * k + 0] = m_Lazy[2 * k + 1] = m_Lazy[k] / 2;
                    m_LazyFlag[2 * k + 0] = m_LazyFlag[2 * k + 1] = Update_Reset;
                }
                m_Seg[k] = m_Lazy[k];
                m_Lazy[k] = 0;
                m_LazyFlag[k] = None;
            }
        }
        // 区間 [a, b) に対して x を足します O(log N)
        // そのうち m_Seg のインデックス k で管理される区間 [l, r) に対して処理します
        // 0-indexed
        void AddImpl(ll a, ll b, ll x, ll k, ll l, ll r) {
            Propagate(k);   // 管理範囲を遅延評価
            if(b <= l || r <= a) { return; }   // 範囲外
            if(a <= l && r <= b) {
                // 完全に包含しているなら
                // 管理している範囲の要素数 * x だけ加算すればよい
                m_Lazy[k] += (r - l) * x;
                m_LazyFlag[k] = Update_Add;
                // その後遅延評価
                Propagate(k);
            }
            else {
                // 範囲が中途半端なら再帰
                AddImpl(a, b, x, 2 * k + 0, l, (l + r) >> 1);
                AddImpl(a, b, x, 2 * k + 1, (l + r) >> 1, r);
                m_Seg[k] = m_Seg[2 * k + 0] + m_Seg[2 * k + 1];
            }
        };
        // 区間 [a, b) 全ての要素を x にします O(log N)
        // そのうち m_Seg のインデックス k で管理される区間 [l, r) に対して処理します
        // 0-indexed
        void ResetImpl(ll a, ll b, ll x, ll k, ll l, ll r) {
            Propagate(k);
            if(b <= l || r <= a) { return; }
            if(a <= l && r <= b) {
                m_Lazy[k] = (r - l) * x;
                m_LazyFlag[k] = Update_Reset;
                // その後遅延評価
                Propagate(k);
            }
            else {
                // 範囲が中途半端なら再帰
                ResetImpl(a, b, x, 2 * k + 0, l, (l + r) >> 1);
                ResetImpl(a, b, x, 2 * k + 1, (l + r) >> 1, r);
                m_Seg[k] = m_Seg[2 * k + 0] + m_Seg[2 * k + 1];
            }
        };
        // 区間 [a,b) の総和を返すために、
        // そのうち m_Seg のインデックス k で管理される区間 [l, r) に対して処理します
        // O(log N)
        ll QueryImpl(ll a, ll b, ll k, ll l, ll r) {
            Propagate(k);
            if(b <= l || r <= a) { return 0; }
            if(a <= l && r <= b) { return m_Seg[k]; }
            return QueryImpl(a, b, 2 * k + 0, l, (l + r) >> 1) +
                   QueryImpl(a, b, 2 * k + 1, (l + r) >> 1, r);
        }

    private:
        ll m_Size;                  // セグ木の要素数
        vector<ll> m_Seg;           // セグ木本体。一次元で管理
        vector<ll> m_Lazy;          // 遅延評価伝搬配列
        vector<ll> m_LazyFlag;      // どのタイプの遅延評価を行うかのフラグ
};

// [lb, ub) の範囲で val 以下の要素で最大のもののインデックスを返す
// なければ -1 を返す
// 同じ数が複数ある場合は一番小さいインデックスを返す
static inline ll bin_search4(const vector< pair<ll, ll> >& v, ll lb, ll ub, ll val) {
    lb--; ub--;
    while(ub - lb > 1) {
        ll mid = (lb + ub) / 2;
        if(v[mid].first >= val) { ub = mid; }
        else { lb = mid; }
    }
    // この時点で lb + 1 = ub
    if(v[ub].first <= val) { return ub; }
    if(lb < 0 || v[lb].first > val) { return -1; }
    return lb;
}

ll N, D, A;
vector< pair<ll, ll> > XH;

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

    cin >> N >> D >> A;
    REP(i, N) {
        ll x, h;
        cin >> x >> h;
        XH.push_back(make_pair(x, h));
    }

    SORT(XH);
    LazySegmentTree lst(N);     // 各モンスターに与えたダメージ
    REP(i, N) {
        lst.Set(i, 0);
    }
    lst.Build();

    ll ans = 0;
    REP(i, N) {
        ll cur_h = XH[i].second - lst.Query(i, i + 1);
        DBG("i: %lld cur_h: %lld XH[i].second: %lld lst.Query(i, i + 1): %lld\n", i, cur_h, XH[i].second, lst.Query(i, i + 1));
        if(cur_h <= 0) { continue; }
        ll cnt = cur_h / A;
        DBG("  cnt: %lld\n", cnt);
        if(cur_h % A != 0) { cnt++; }
        ans += cnt;
        ll damage = A * cnt;
        // ダメージが届く範囲
        ll x_r = XH[i].first + (2 * D);
        assert(x_r >= i);
        ll range = bin_search4(XH, i, N, x_r);
        lst.Add(i, range + 1, damage);
    }
    printf("%lld\n", ans);

    return 0;
}