Problem p03185 (C++)

Buggy submission (status: Time Limit Exceeded):
#include <bits/stdc++.h>
using namespace std;

using i64 = int64_t;

#define rep(i, x, y)                                                           \
  for (i64 i = i64(x), i##_max_for_repmacro = i64(y);                          \
       i < i##_max_for_repmacro; ++i)
#define debug(x) #x << "=" << (x)

#ifdef DEBUG
#define _GLIBCXX_DEBUG
#define print(x) std::cerr << debug(x) << " (L:" << __LINE__ << ")" << std::endl
#else
#define print(x)
#endif

const int inf = 1.01e9;
const i64 inf64 = 4.01e18;
const double eps = 1e-9;

template <typename T, typename U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
  os << "(" << p.first << ", " << p.second << ")";
  return os;
}

template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec) {
  os << "[";
  for (const auto &v : vec) {
    os << v << ",";
  }
  os << "]";
  return os;
}

template <typename T> bool chmin(T &a, const T &b) {
  if (a > b) {
    a = b;
    return true;
  }
  return false;
}

template <typename T> bool chmax(T &a, const T &b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}

template <typename T, size_t size> void fill(T (&ary)[size], const T &val) {
  fill_n((T *)ary, size, val);
}

/*
    直線集合L={f_i =
   a_i*x+b_i}と与えられたクエリxに対してmin(f_i(x))を求めることができる.
    この実装では追加される直線の傾きが単調非増加である場合のみ対応している.

    add: O(N)
    min(クエリが単調非減少の場合): O(Q)
    min(一般の場合): O(QlogN)
    N := 直線の個数
    Q := クエリの個数

    verified by
   https://beta.atcoder.jp/contests/colopl2018-final-open/submissions/3644416

    TODO: 最大値クエリの場合を検証する
*/

template <typename T> struct convex_hull_trick {
  static bool ge(T a, T b) { return a >= b; }

  static bool le(T a, T b) { return a <= b; }

  bool is_monotonicx;
  int head;
  function<bool(T, T)> comp;
  vector<pair<T, T>> lines;

  // is_monotonic := クエリは単調非減少か?
  // min_or_max := trueならば最小値を求める, falseならば最大値を求める
  convex_hull_trick(bool is_monotonicx, bool min_or_max)
      : is_monotonicx(is_monotonicx), head(0) {
    comp = min_or_max ? ge : le;
  }

  bool need(pair<T, T> &l, pair<T, T> &m, pair<T, T> &n) {
    return (n.second - m.second) * (m.first - l.first) <
           (m.second - l.second) * (n.first - m.first);
  }

  // 直線f(x)=ax+bを追加する.
  // aは単調非増加である必要がある
  void add(T a, T b) {
    auto line = make_pair(a, b);
    while (lines.size() >= 2 and
           !need(*(lines.end() - 2), lines.back(), line)) {
      lines.pop_back();
    }
    lines.push_back(line);
  }

  T f(int i, T x) { return lines[i].first * x + lines[i].second; }

  // f_i(x)の最小値(or最大値)
  T min(T x) {
    if (is_monotonicx) {
      while (lines.size() - head >= 2 and comp(f(head, x), f(head + 1, x)))
        ++head;
      return f(head, x);
    } else {
      int lb = 0, ub = lines.size();
      while (ub - lb > 1) {
        int mid = (lb + ub) / 2;
        (mid == 0 or comp(f(mid - 1, x), f(mid, x)) ? lb : ub) = mid;
      }
      rep(i, 0, lines.size()) assert(comp(f(i, x), f(lb, x)));
      return f(lb, x);
    }
  }
};

void solve() {
  // const i64 mod = 1'000'000'007;

  i64 N, C;
  cin >> N >> C;

  vector<i64> h(N);
  rep(i, 0, N) { cin >> h[i]; }

  const i64 maxn = 200000;
  static i64 dp[maxn];
  fill(dp, maxn);

  convex_hull_trick<i64> cht(false, false);

  dp[0] = 0;
  cht.add(2 * h[0], -h[0] * h[0] - dp[0]);
  rep(i, 1, N) {
    dp[i] = h[i] * h[i] + C - cht.min(h[i]);
    cht.add(2 * h[i], -h[i] * h[i] - dp[i]);
  }

  cout << dp[N - 1] << endl;
}

int main() {
  std::cin.tie(0);
  std::ios::sync_with_stdio(false);
  cout.setf(ios::fixed);
  cout.precision(16);
  solve();
  return 0;
}


Fixed submission:
#include <bits/stdc++.h>
using namespace std;

using i64 = int64_t;

#define rep(i, x, y)                                                           \
  for (i64 i = i64(x), i##_max_for_repmacro = i64(y);                          \
       i < i##_max_for_repmacro; ++i)
#define debug(x) #x << "=" << (x)

#ifdef DEBUG
#define _GLIBCXX_DEBUG
#define print(x) std::cerr << debug(x) << " (L:" << __LINE__ << ")" << std::endl
#else
#define print(x)
#endif

const int inf = 1.01e9;
const i64 inf64 = 4.01e18;
const double eps = 1e-9;

template <typename T, typename U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
  os << "(" << p.first << ", " << p.second << ")";
  return os;
}

template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec) {
  os << "[";
  for (const auto &v : vec) {
    os << v << ",";
  }
  os << "]";
  return os;
}

template <typename T> bool chmin(T &a, const T &b) {
  if (a > b) {
    a = b;
    return true;
  }
  return false;
}

template <typename T> bool chmax(T &a, const T &b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}

template <typename T, size_t size> void fill(T (&ary)[size], const T &val) {
  fill_n((T *)ary, size, val);
}

/*
    直線集合L={f_i =
   a_i*x+b_i}と与えられたクエリxに対してmin(f_i(x))を求めることができる.
    この実装では追加される直線の傾きが単調非増加である場合のみ対応している.

    add: O(N)
    min(クエリが単調非減少の場合): O(Q)
    min(一般の場合): O(QlogN)
    N := 直線の個数
    Q := クエリの個数

    verified by
   https://beta.atcoder.jp/contests/colopl2018-final-open/submissions/3644416

    TODO: 最大値クエリの場合を検証する
*/

template <typename T> struct convex_hull_trick {
  static bool ge(T a, T b) { return a >= b; }

  static bool le(T a, T b) { return a <= b; }

  bool is_monotonicx;
  int head;
  function<bool(T, T)> comp;
  vector<pair<T, T>> lines;

  // is_monotonic := クエリは単調非減少か?
  // min_or_max := trueならば最小値を求める, falseならば最大値を求める
  convex_hull_trick(bool is_monotonicx, bool min_or_max)
      : is_monotonicx(is_monotonicx), head(0) {
    comp = min_or_max ? ge : le;
  }

  bool need(pair<T, T> &l, pair<T, T> &m, pair<T, T> &n) {
    return (n.second - m.second) * (m.first - l.first) <
           (m.second - l.second) * (n.first - m.first);
  }

  // 直線f(x)=ax+bを追加する.
  // aは単調非増加である必要がある
  void add(T a, T b) {
    auto line = make_pair(a, b);
    while (lines.size() >= 2 and
           !need(*(lines.end() - 2), lines.back(), line)) {
      lines.pop_back();
    }
    lines.push_back(line);
  }

  T f(int i, T x) { return lines[i].first * x + lines[i].second; }

  // f_i(x)の最小値(or最大値)
  T min(T x) {
    if (is_monotonicx) {
      while (lines.size() - head >= 2 and comp(f(head, x), f(head + 1, x)))
        ++head;
      return f(head, x);
    } else {
      int lb = 0, ub = lines.size();
      while (ub - lb > 1) {
        int mid = (lb + ub) / 2;
        (mid == 0 or comp(f(mid - 1, x), f(mid, x)) ? lb : ub) = mid;
      }
      rep(i, 0, lines.size()) assert(comp(f(i, x), f(lb, x)));
      return f(lb, x);
    }
  }
};

void solve() {
  // const i64 mod = 1'000'000'007;

  i64 N, C;
  cin >> N >> C;

  vector<i64> h(N);
  rep(i, 0, N) { cin >> h[i]; }

  const i64 maxn = 200000;
  static i64 dp[maxn];
  fill(dp, maxn);

  convex_hull_trick<i64> cht(true, false);

  dp[0] = 0;
  cht.add(2 * h[0], -h[0] * h[0] - dp[0]);
  rep(i, 1, N) {
    dp[i] = h[i] * h[i] + C - cht.min(h[i]);
    cht.add(2 * h[i], -h[i] * h[i] - dp[i]);
  }

  cout << dp[N - 1] << endl;
}

int main() {
  std::cin.tie(0);
  std::ios::sync_with_stdio(false);
  cout.setf(ios::fixed);
  cout.precision(16);
  solve();
  return 0;
}