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# (Mono 4.6.2.0) (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Linq;
using static Input;
using static Prog;
using NX = System.Int64;

public class Solver
{
    public void Solve()
    {
        int N = NextInt();
        NX D = NextLong() * 2, A = NextLong();
        List<Tuple<NX, NX>> input = new List<Tuple<NX, NX>>();
        for (int i = 0; i < N; i++) { input.Add(new Tuple<NX, NX>(NextLong(), NextLong())); }
        var d = input.OrderBy(v => v.Item1).ToList();

        LazySegTree LST = new LazySegTree(N, 0, (x, y) => (x + y));
        for (int i = 0; i < N; i++) { LST.Insert(i, d[i].Item2); }

        NX ans = 0;
        for (int i = 0; i < N; i++)
        {
            if (LST.Query(i, i + 1) <= 0) continue;
            int ok = -1, ng = N;
            while (ng - ok != 1)
            {
                int mid = (ok + ng) / 2;
                if (d[mid].Item1 - d[i].Item1 <= D) ok = mid;
                else ng = mid;
            }
            //d[i].HP を超えるだけ打つ
            NX count = LST.Query(i, i + 1) / A + (LST.Query(i, i + 1) % A == 0 ? 0 : 1);
            //Console.WriteLine(d[i].Item1 + " -> " + d[ok].Item1 + " : " + count);
            ans += count;
            LST.InsertRange(i, ok + 1, -count * A);

        }
        Console.WriteLine(ans);
    }

}
public class LazySegTree
{
    private List<NX> node = new List<NX>();
    private List<NX> lazy = new List<NX>();
    private static int size = 1;
    private static NX lim;
    private static Func<NX, NX, NX> update_func;
    public LazySegTree(int n, NX m, Func<NX, NX, NX> func)
    {
        while (size < n) size *= 2;
        node = Enumerable.Range(0, 2 * size - 1).Select(v => m).ToList();
        lazy = Enumerable.Range(0, 2 * size - 1).Select(v => m).ToList();
        lim = m;
        update_func = func;
    }
    public void Insert(int pos, NX val)
    {
        pos += size - 1;
        node[pos] = val;
        while (pos != 0)
        {
            pos = (pos % 2 == 0 ? pos / 2 - 1 : pos / 2);
            node[pos] = update_func(node[pos * 2 + 1], node[pos * 2 + 2]);
        }
    }
    public void InsertRange(int ser_l, int ser_r, NX val, int index = 0, int now_l = 0, int now_r = 0)
    {
        if (2 * size < index) return;
        if (now_r <= now_l) now_r = size;
        Convey(index);
        if (ser_r <= now_l || now_r <= ser_l) return;
        if (ser_l <= now_l && now_r <= ser_r) { lazy[index] += (now_r - now_l) * val; Convey(index); }
        else
        {
            //Left
            InsertRange(ser_l, ser_r, val, index * 2 + 1, now_l, (now_l + now_r) / 2);
            //Reft
            InsertRange(ser_l, ser_r, val, index * 2 + 2, (now_l + now_r) / 2, now_r);
            node[index] = update_func(node[index * 2 + 1], node[index * 2 + 2]);
        }
    }


    public NX Query(int sel_l, int sel_r, int index = 0, int now_l = 0, int now_r = 0)
    {
        if (now_r <= now_l) now_r = size;
        if (now_r <= sel_l || sel_r <= now_l) return lim;
        Convey(index);
        if (sel_l <= now_l && now_r <= sel_r) { return node[index]; }
        NX left = Query(sel_l, sel_r, index * 2 + 1, now_l, (now_r + now_l) / 2);
        NX right = Query(sel_l, sel_r, index * 2 + 2, (now_r + now_l) / 2, now_r);
        return update_func(left, right);
    }
    void Convey(int index)
    {
        if (lazy[index] != 0)
        {
            node[index] += lazy[index];
            if (index < size - 1)
            {
                lazy[index * 2 + 1] += lazy[index] / 2;
                lazy[index * 2 + 2] += lazy[index] / 2;
            }
            lazy[index] = 0;
        }
    }
}

public class Prog
{
    public const long MOD = 1000000007;
    public const int INF = 1000000007;
    public struct Pair { public int x, y; public Pair(int a, int b) { x = a; y = b; } }
    static void Main()
    {
        var sw = new System.IO.StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false };
        Console.SetOut(sw);
        new Solver().Solve();
        Console.Out.Flush();
        return;
    }
}

public class Input
{
    private static Queue<string> q = new Queue<string>();
    private static void Confirm() { if (q.Count == 0) foreach (var s in Console.ReadLine().Split(' ')) q.Enqueue(s); }
    public static int NextInt() { Confirm(); return int.Parse(q.Dequeue()); }
    public static long NextLong() { Confirm(); return long.Parse(q.Dequeue()); }
    public static string NextString() { Confirm(); return q.Dequeue(); }
    public static double NextDouble() { Confirm(); return double.Parse(q.Dequeue()); }
    public static int[] LineInt() { return Console.ReadLine().Split(' ').Select(int.Parse).ToArray(); }
    public static long[] LineLong() { return Console.ReadLine().Split(' ').Select(long.Parse).ToArray(); }
    public static string[] LineString() { return Console.ReadLine().Split(' ').ToArray(); }
    public static double[] LineDouble() { return Console.ReadLine().Split(' ').Select(double.Parse).ToArray(); }
    public long Abs(long a, long b) => Math.Abs(a - b);
}