#include <iostream>
#include <string>
#include <algorithm>
#include <cmath>
#include <functional>
#include <vector>
#include <queue>
#include <deque>
#include <map>
#include <set>
#define Inf 1000000000
#define nmax_def 110000
#define mod 1000000007
#define rep(i,n) for(int (i)=0;(i)<(n);(i)++)
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<bool> vb;
class LazySegmentTree {
public:
    int listnum;
    int listnum_pow2 = 1;
    vl node_val, lazy_val;

    void LazySegmentTree_ini(vl node_val_ini); // 初期化 (ノード更新あり)
    void update(int x, ll val_update); // 1要素の代入 (ノード更新あり)
    void eval(int nodetmp, int l, int r); // 遅延評価
    ll val_x(int x); // 値の取得
    ll getmin(int search_L, int search_R); // 最小値の取得
    void add(int search_L, int search_R, ll val_add); // 足す (ノード更新あり)
    ll getsum(int search_L, int search_R); // 区間和

private:
    ll getmin_sbrt(int search_L, int search_R, int nodetmp, int L, int R);
    void add_sbrt(int search_L, int search_R, ll val_add, int nodetmp, int L, int R);
    ll getsum_sbrt(int search_L, int search_R, int nodetmp, int L, int R);
};

void LazySegmentTree::LazySegmentTree_ini(vl node_val_ini) { // 初期化 (ノード更新あり)
    listnum = node_val_ini.size();
    listnum_pow2 = 1;
    while (listnum_pow2 < listnum)
        listnum_pow2 *= 2;
    for (int i = listnum; i < listnum_pow2; i++) {
        //node_val_ini.push_back(INF); // 最小値
        node_val_ini.push_back(0); // 和
    }

    node_val.resize(2 * listnum_pow2 - 1);
    lazy_val.resize(2 * listnum_pow2 - 1, 0);

    for (int i = 0; i < listnum_pow2; i++)
        node_val[i + listnum_pow2 - 1] = node_val_ini[i];
    for (int i = listnum_pow2 - 2; i >= 0; i--) {
        //node_val[i] = min(node_val[i * 2 + 1], node_val[i * 2 + 2]); // 最小値
        node_val[i] = node_val[i * 2 + 1] + node_val[i * 2 + 2]; // 和
    }
}

void LazySegmentTree::update(int x, ll val_update) { // 1要素の代入 (ノード更新あり)
    int nodetmp = x + listnum_pow2 - 1;
    node_val[nodetmp] = val_update;
    while (nodetmp > 0) {
        nodetmp = (nodetmp - 1) / 2;
        //node_val[nodetmp] = min(node_val[2 * nodetmp + 1], node_val[2 * nodetmp + 2]); // 最小値
        node_val[nodetmp] = node_val[2 * nodetmp + 1] + node_val[2 * nodetmp + 2]; // 和
    }
    return;
}

void LazySegmentTree::eval(int nodetmp, int L, int R) {
    if (lazy_val[nodetmp] != 0) {
        //node_val[nodetmp] = min(node_val[nodetmp], lazy_val[nodetmp]); // 最小値
        node_val[nodetmp] += lazy_val[nodetmp]; // 和
        if (R - L > 1) {
            lazy_val[2 * nodetmp + 1] += lazy_val[nodetmp] / 2;
            lazy_val[2 * nodetmp + 2] += lazy_val[nodetmp] / 2;
        }
        lazy_val[nodetmp] = 0;
    }
}

ll LazySegmentTree::val_x(int x) { // 値の取得
    int nodetmp = x + listnum_pow2 - 1;
    ll ans = node_val[nodetmp];
    return ans;
}

ll LazySegmentTree::getmin_sbrt(int search_L, int search_R, int nodetmp, int L, int R) { // 最小値の取得
    eval(nodetmp, L, R);
    if (R <= search_L || search_R <= L)
        return Inf;
    if (search_L <= L && R <= search_R) {
        eval(nodetmp, L, R);
        return node_val[nodetmp];
    }

    int M = (L + R) / 2;
    int nodenew_L = 2 * nodetmp + 1;
    ll node_val_min_L = getmin_sbrt(search_L, search_R, nodenew_L, L, M);
    int nodenew_R = 2 * nodetmp + 2;
    ll node_val_min_R = getmin_sbrt(search_L, search_R, nodenew_R, M, R);
    ll node_val_min = min(node_val_min_L, node_val_min_R);
    return node_val_min;
}

ll LazySegmentTree::getmin(int search_L, int search_R) { // 最小値の取得
    ll ans = getmin_sbrt(search_L, search_R, 0, 0, listnum_pow2);
    return ans;
}

void LazySegmentTree::add_sbrt(int search_L, int search_R, ll val_add, int nodetmp, int L, int R) { // 足す (ノード更新あり)
    eval(nodetmp, L, R);
    if (search_R <= L || R <= search_L)
        return;
    if (search_L <= L && R <= search_R) {
        //lazy_val[nodetmp] += val_add; // 最小値
        lazy_val[nodetmp] += (R - L) * val_add; // 和
        return;
    }

    int M = (L + R) / 2;
    int nodenew;
    int nodenew_L = 2 * nodetmp + 1;
    add_sbrt(search_L, search_R, val_add, nodenew_L, L, M);
    int nodenew_R = 2 * nodetmp + 2;
    add_sbrt(search_L, search_R, val_add, nodenew_R, M, R);
    //node_val[nodetmp] = min(node_val[nodenew_L], node_val[nodenew_R]); // 最小値
    node_val[nodetmp] = node_val[nodenew_L] + node_val[nodenew_R]; // 和
}

void LazySegmentTree::add(int search_L, int search_R, ll val_add) { // 足す (ノード更新あり)
    add_sbrt(search_L, search_R, val_add, 0, 0, listnum_pow2);
    return;
}

ll LazySegmentTree::getsum_sbrt(int search_L, int search_R, int nodetmp, int L, int R) { // 区間和
    eval(nodetmp, L, R);
    if (search_R <= L || R <= search_L)
        return 0;
    if (search_L <= L && R <= search_R) {
        return node_val[nodetmp];
    }

    int M = (L + R) / 2;
    int nodenew_L = 2 * nodetmp + 1;
    ll node_val_min_L = getsum_sbrt(search_L, search_R, nodenew_L, L, M);
    int nodenew_R = 2 * nodetmp + 2;
    ll node_val_min_R = getsum_sbrt(search_L, search_R, nodenew_R, M, R);
    ll node_val_min = node_val_min_L + node_val_min_R;
    return node_val_min;
}

ll LazySegmentTree::getsum(int search_L, int search_R) { // 区間和
    ll ans = getsum_sbrt(search_L, search_R, 0, 0, listnum_pow2);
    return ans;
}

int main() {
    ll N, D, A;
    cin >> N >> D >> A;
    ll diff = 2 * D;
    vector<pll> XH(N);
    rep(i, N)
        cin >> XH[i].first >> XH[i].second;
    sort(XH.begin(), XH.end(), less<pll>());
    vl X(N);
    vl H(N);
    rep(i, N) {
        X[i] = XH[i].first;
        H[i] = XH[i].second;
    }
    vl a = H;
    LazySegmentTree Tree;
    Tree.LazySegmentTree_ini(a);
    ll j = 0;
    ll ans = 0;
    rep(i, N) {
        if (Tree.getsum(i, i + 1) <= 0)
            continue;
        while (1) {
            if (j == N)
                break;
            if (X[j] - X[i] > diff)
                break;
            j++;
        }
        ll subtmp = Tree.getsum(i, i + 1) / A;
        if (Tree.getsum(i, i + 1) % A != 0)
            subtmp++;
        ans += subtmp;
        ll subsub = subtmp * A;
        Tree.add(i, j, -subsub);
    }
    cout << ans << endl;
    return 0;
}

Measured memory_bytes: 19172