Problem p02788 (C++)

Buggy submission (status: Runtime Error):
#define _CRT_SECURE_NO_WARNINGS
#define _USE_MATH_DEFINES
#include <algorithm>
#include <array>
#include <bitset>
#include <cctype>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <utility>
#include <vector>
using namespace std;
#define INF 0x3f3f3f3f
#define INFLL 0x3f3f3f3f3f3f3f3fLL
// #define MOD 998244353
#define MOD 1000000007
#define mp make_pair
#define mt make_tuple
#define pb push_back
#define eb emplace_back
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int, int> pint;
typedef pair<ll, ll> pll;
typedef tuple<int, int, int> tint;
typedef vector<int> vint;
typedef vector<ll> vll;
typedef vector<ull> vull;
typedef vector<pint> vpint;
int dx[8] = {0, 0, -1, 1, 1, 1, -1, -1};
int dy[8] = {-1, 1, 0, 0, 1, -1, 1, -1};
const int SIZE = 100050;
// ↑templete
#define int long long
// ↓区間和を求めるSegmentTree
struct SegmentTreeSum {
private:
  int n;
  vector<int> node;

public:
  // 元配列 v をセグメント木で表現する
  SegmentTreeSum(vector<int> v) {
    // 最下段のノード数は元配列のサイズ以上になる最小の 2 冪 -> これを n とおく
    // セグメント木全体で必要なノード数は 2n-1 個である
    int sz = v.size();
    n = 1;
    while (n < sz)
      n *= 2;
    node.resize(2 * n - 1, 0);

    // 最下段に値を入れたあとに、下の段から順番に値を入れる
    // 値を入れるには、自分の子の 2 値を参照すれば良い
    for (int i = 0; i < sz; i++)
      node[i + n - 1] = v[i];
    for (int i = n - 2; i >= 0; i--)
      node[i] = (node[2 * i + 1] + node[2 * i + 2]);
  }
  void update(int x, int val) {
    // 最下段のノードにアクセスする
    x += (n - 1);

    // 最下段のノードを更新したら、あとは親に上って更新していく
    node[x] = val;
    while (x > 0) {
      x = (x - 1) / 2;
      node[x] = (node[2 * x + 1] + node[2 * x + 2]);
    }
  }
  int getsum(int a, int b, int k = 0, int l = 0, int r = -1) {
    // 最初に呼び出されたときの対象区間は [0, n)
    if (r < 0)
      r = n;

    // 要求区間と対象区間が交わらない -> 適当に返す
    if (r <= a || b <= l)
      return 0;

    // 要求区間が対象区間を完全に被覆 -> 対象区間を答えの計算に使う
    if (a <= l && r <= b)
      return node[k];

    // 要求区間が対象区間の一部を被覆 -> 子について探索を行う
    // 左側の子を vl ・ 右側の子を vr としている
    // 新しい対象区間は、現在の対象区間を半分に割ったもの
    int vl = getsum(a, b, 2 * k + 1, l, (l + r) / 2);
    int vr = getsum(a, b, 2 * k + 2, (l + r) / 2, r);
    return (vl + vr);
  }
};
// ↑区間和を求めるSegmentTree
signed main() {

  ll N, D, A;
  cin >> N >> D >> A;
  vector<pll> monsters;
  vll X;
  for (int i = 0; i < N; i++) {
    ll x, h;
    cin >> x >> h;
    monsters.eb(x, h);
    X.pb(x);
  }
  sort(monsters.begin(), monsters.end());
  sort(X.begin(), X.end());

  vll ini(SIZE);
  SegmentTreeSum dam(ini);
  ll ans = 0;
  for (int i = 0; i < N; i++) {
    int x, h;
    tie(x, h) = monsters[i];
    // 現在のモンスタiの体力
    ll hp = h - dam.getsum(0, i + 1);
    // cout<<"!"<<i<<" "<<hp<<endl;
    if (hp <= 0)
      continue;

    // 叩く回数
    ll attack = (hp + A - 1) / A;
    ans += attack;
    // どこまで届くか？
    ll right = (upper_bound(X.begin(), X.end(), ll(x + 2 * D)) - X.begin());
    // cout<<"right : "<<right<<endl;
    //  //叩く
    dam.update(i, dam.getsum(i, i + 1) + A * attack);
    dam.update(right, dam.getsum(right, right + 1) - A * attack);

    // cout<<"damage"<<endl;
    // for(int j=0;j<=N;j++)
    // 	cout<<dam.getsum(j, j+1)<<" ";
    // cout<<endl;
  }
  cout << ans << endl;

  return 0;
}

Fixed submission:
#define _CRT_SECURE_NO_WARNINGS
#define _USE_MATH_DEFINES
#include <algorithm>
#include <array>
#include <bitset>
#include <cctype>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <utility>
#include <vector>
using namespace std;
#define INF 0x3f3f3f3f
#define INFLL 0x3f3f3f3f3f3f3f3fLL
// #define MOD 998244353
#define MOD 1000000007
#define mp make_pair
#define mt make_tuple
#define pb push_back
#define eb emplace_back
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int, int> pint;
typedef pair<ll, ll> pll;
typedef tuple<int, int, int> tint;
typedef vector<int> vint;
typedef vector<ll> vll;
typedef vector<ull> vull;
typedef vector<pint> vpint;
int dx[8] = {0, 0, -1, 1, 1, 1, -1, -1};
int dy[8] = {-1, 1, 0, 0, 1, -1, 1, -1};
const int SIZE = 200050;
// ↑templete
#define int long long
// ↓区間和を求めるSegmentTree
struct SegmentTreeSum {
private:
  int n;
  vector<int> node;

public:
  // 元配列 v をセグメント木で表現する
  SegmentTreeSum(vector<int> v) {
    // 最下段のノード数は元配列のサイズ以上になる最小の 2 冪 -> これを n とおく
    // セグメント木全体で必要なノード数は 2n-1 個である
    int sz = v.size();
    n = 1;
    while (n < sz)
      n *= 2;
    node.resize(2 * n - 1, 0);

    // 最下段に値を入れたあとに、下の段から順番に値を入れる
    // 値を入れるには、自分の子の 2 値を参照すれば良い
    for (int i = 0; i < sz; i++)
      node[i + n - 1] = v[i];
    for (int i = n - 2; i >= 0; i--)
      node[i] = (node[2 * i + 1] + node[2 * i + 2]);
  }
  void update(int x, int val) {
    // 最下段のノードにアクセスする
    x += (n - 1);

    // 最下段のノードを更新したら、あとは親に上って更新していく
    node[x] = val;
    while (x > 0) {
      x = (x - 1) / 2;
      node[x] = (node[2 * x + 1] + node[2 * x + 2]);
    }
  }
  int getsum(int a, int b, int k = 0, int l = 0, int r = -1) {
    // 最初に呼び出されたときの対象区間は [0, n)
    if (r < 0)
      r = n;

    // 要求区間と対象区間が交わらない -> 適当に返す
    if (r <= a || b <= l)
      return 0;

    // 要求区間が対象区間を完全に被覆 -> 対象区間を答えの計算に使う
    if (a <= l && r <= b)
      return node[k];

    // 要求区間が対象区間の一部を被覆 -> 子について探索を行う
    // 左側の子を vl ・ 右側の子を vr としている
    // 新しい対象区間は、現在の対象区間を半分に割ったもの
    int vl = getsum(a, b, 2 * k + 1, l, (l + r) / 2);
    int vr = getsum(a, b, 2 * k + 2, (l + r) / 2, r);
    return (vl + vr);
  }
};
// ↑区間和を求めるSegmentTree
signed main() {

  ll N, D, A;
  cin >> N >> D >> A;
  vector<pll> monsters;
  vll X;
  for (int i = 0; i < N; i++) {
    ll x, h;
    cin >> x >> h;
    monsters.eb(x, h);
    X.pb(x);
  }
  sort(monsters.begin(), monsters.end());
  sort(X.begin(), X.end());

  vll ini(SIZE);
  SegmentTreeSum dam(ini);
  ll ans = 0;
  for (int i = 0; i < N; i++) {
    int x, h;
    tie(x, h) = monsters[i];
    // 現在のモンスタiの体力
    ll hp = h - dam.getsum(0, i + 1);
    // cout<<"!"<<i<<" "<<hp<<endl;
    if (hp <= 0)
      continue;

    // 叩く回数
    ll attack = (hp + A - 1) / A;
    ans += attack;
    // どこまで届くか？
    ll right = (upper_bound(X.begin(), X.end(), ll(x + 2 * D)) - X.begin());
    // cout<<"right : "<<right<<endl;
    //  //叩く
    dam.update(i, dam.getsum(i, i + 1) + A * attack);
    dam.update(right, dam.getsum(right, right + 1) - A * attack);

    // cout<<"damage"<<endl;
    // for(int j=0;j<=N;j++)
    // 	cout<<dam.getsum(j, j+1)<<" ";
    // cout<<endl;
  }
  cout << ans << endl;

  return 0;
}