Problem p02868 (C++)

Buggy submission (status: Time Limit Exceeded):
#ifdef LOCAL
#define _GLIBCXX_DEBUG
#define __clock__
#else
#pragma GCC optimize("Ofast")
// #define NDEBUG
#endif
#define __precision__ 10
#define iostream_untie true
#define debug_stream std::cerr

#include <algorithm>
#include <bitset>
#include <cassert>
#include <chrono>
#include <complex>
#include <cstring>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <unordered_map>
#include <unordered_set>

#define all(v) std::begin(v), std::end(v)
#define rall(v) std::rbegin(v), std::rend(v)
#define odd(n) ((n)&1)
#define even(n) (not __odd(n))
#define __popcount(n) __builtin_popcountll(n)
#define __clz32(n) __builtin_clz(n)
#define __clz64(n) __builtin_clzll(n)
#define __ctz32(n) __builtin_ctz(n)
#define __ctz64(n) __builtin_ctzll(n)

using i32 = int_least32_t;
using i64 = int_least64_t;
using u32 = uint_least32_t;
using u64 = uint_least64_t;
using pii = std::pair<i32, i32>;
using pll = std::pair<i64, i64>;
template <class T> using heap = std::priority_queue<T>;
template <class T>
using rheap = std::priority_queue<T, std::vector<T>, std::greater<T>>;
template <class K, class T> using hashmap = std::unordered_map<K, T>;
template <class T> using hashset = std::unordered_set<T>;

namespace execution {
using namespace std::chrono;
system_clock::time_point start_time, end_time;
long long get_elapsed_time() {
  end_time = system_clock::now();
  return duration_cast<milliseconds>(end_time - start_time).count();
}
void print_elapsed_time() {
  std::cerr << "\n----- Exec time : " << get_elapsed_time() << " ms -----\n\n";
}
struct setupper {
  setupper() {
    if (iostream_untie)
      std::ios::sync_with_stdio(false), std::cin.tie(nullptr);
    std::cout << std::fixed << std::setprecision(__precision__);
#ifdef stderr_path
    if (freopen(stderr_path, "a", stderr)) {
      std::cerr << std::fixed << std::setprecision(__precision__);
    }
#endif
#ifdef stdout_path
    if (not freopen(stdout_path, "w", stdout)) {
      freopen("CON", "w", stdout);
      std::cerr << "Failed to open the stdout file\n\n";
    }
    std::cout << "";
#endif
#ifdef stdin_path
    if (not freopen(stdin_path, "r", stdin)) {
      freopen("CON", "r", stdin);
      std::cerr << "Failed to open the stdin file\n\n";
    }
#endif
#ifdef LOCAL
    std::cerr << "----- stderr at LOCAL -----\n\n";
    atexit(print_elapsed_time);
#else
    fclose(stderr);
#endif
#ifdef __clock__
    start_time = system_clock::now();
#endif
  }
} __setupper;
class myclock_t {
  system_clock::time_point built_pt, last_pt;
  int built_ln, last_ln;
  std::string built_func, last_func;
  bool is_built;

public:
  myclock_t() : is_built(false) {}
  void build(int crt_ln, const std::string &crt_func) {
    is_built = true, last_pt = built_pt = system_clock::now(),
    last_ln = built_ln = crt_ln, last_func = built_func = crt_func;
  }
  void set(int crt_ln, const std::string &crt_func) {
    if (is_built)
      last_pt = system_clock::now(), last_ln = crt_ln, last_func = crt_func;
    else
      debug_stream << "[ " << crt_ln << " : " << crt_func << " ] "
                   << "myclock_t::set failed (yet to be built!)\n";
  }
  void get(int crt_ln, const std::string &crt_func) {
    if (is_built) {
      system_clock::time_point crt_pt(system_clock::now());
      long long diff = duration_cast<milliseconds>(crt_pt - last_pt).count();
      debug_stream << diff << " ms elapsed from"
                   << " [ " << last_ln << " : " << last_func << " ]";
      if (last_ln == built_ln)
        debug_stream << " (when built)";
      debug_stream << " to"
                   << " [ " << crt_ln << " : " << crt_func << " ]"
                   << "\n";
      last_pt = built_pt, last_ln = built_ln, last_func = built_func;
    } else {
      debug_stream << "[ " << crt_ln << " : " << crt_func << " ] "
                   << "myclock_t::get failed (yet to be built!)\n";
    }
  }
};
} // namespace execution

#ifdef __clock__
execution::myclock_t __myclock;
#define build_clock() __myclock.build(__LINE__, __func__)
#define set_clock() __myclock.set(__LINE__, __func__)
#define get_clock() __myclock.get(__LINE__, __func__)
#else
#define build_clock() ((void)0)
#define set_clock() ((void)0)
#define get_clock() ((void)0)
#endif

namespace std {
template <class P> void rsort(P __first, P __last) {
  sort(__first, __last, greater<>());
}
template <class T> size_t hash_combine(size_t seed, T const &key) {
  return seed ^ (hash<T>()(key) + 0x9e3779b9 + (seed << 6) + (seed >> 2));
}
template <class T, class U> struct hash<pair<T, U>> {
  size_t operator()(pair<T, U> const &pr) const {
    return hash_combine(hash_combine(0, pr.first), pr.second);
  }
};
template <class tuple_t, size_t index = tuple_size<tuple_t>::value - 1>
struct tuple_hash_calc {
  static size_t apply(size_t seed, tuple_t const &t) {
    return hash_combine(tuple_hash_calc<tuple_t, index - 1>::apply(seed, t),
                        get<index>(t));
  }
};
template <class tuple_t> struct tuple_hash_calc<tuple_t, 0> {
  static size_t apply(size_t seed, tuple_t const &t) {
    return hash_combine(seed, get<0>(t));
  }
};
template <class... T> struct hash<tuple<T...>> {
  size_t operator()(tuple<T...> const &t) const {
    return tuple_hash_calc<tuple<T...>>::apply(0, t);
  }
};
template <class T, class U>
istream &operator>>(std::istream &s, pair<T, U> &p) {
  return s >> p.first >> p.second;
}
template <class T, class U>
ostream &operator<<(std::ostream &s, const pair<T, U> &p) {
  return s << p.first << " " << p.second;
}
template <class T> istream &operator>>(istream &s, vector<T> &v) {
  for (T &e : v)
    s >> e;
  return s;
}
template <class T> ostream &operator<<(ostream &s, const vector<T> &v) {
  bool is_front = true;
  for (const T &e : v) {
    if (not is_front)
      s << ' ';
    else
      is_front = false;
    s << e;
  }
  return s;
}
template <class tuple_t, size_t index> struct tupleos {
  static ostream &apply(ostream &s, const tuple_t &t) {
    tupleos<tuple_t, index - 1>::apply(s, t);
    return s << " " << get<index>(t);
  }
};
template <class tuple_t> struct tupleos<tuple_t, 0> {
  static ostream &apply(ostream &s, const tuple_t &t) { return s << get<0>(t); }
};
template <class... T> ostream &operator<<(ostream &s, const tuple<T...> &t) {
  return tupleos<tuple<T...>, tuple_size<tuple<T...>>::value - 1>::apply(s, t);
}
template <> ostream &operator<<(ostream &s, const tuple<> &t) { return s; }
string revstr(string str) {
  reverse(str.begin(), str.end());
  return str;
}
} // namespace std

#ifdef LOCAL
#define dump(...)                                                              \
  debug_stream << "[ " << __LINE__ << " : " << __FUNCTION__ << " ]\n",         \
      dump_func(#__VA_ARGS__, __VA_ARGS__)
template <class T> void dump_func(const char *ptr, const T &x) {
  debug_stream << '\t';
  for (char c = *ptr; c != '\0'; c = *++ptr)
    if (c != ' ')
      debug_stream << c;
  debug_stream << " : " << x << '\n';
}
template <class T, class... rest_t>
void dump_func(const char *ptr, const T &x, rest_t... rest) {
  debug_stream << '\t';
  for (char c = *ptr; c != ','; c = *++ptr)
    if (c != ' ')
      debug_stream << c;
  debug_stream << " : " << x << ",\n";
  dump_func(++ptr, rest...);
}
#else
#define dump(...) ((void)0)
#endif
template <class P> void read_range(P __first, P __second) {
  for (P i = __first; i != __second; ++i)
    std::cin >> *i;
}
template <class P> void write_range(P __first, P __second) {
  for (P i = __first; i != __second;
       std::cout << (++i == __second ? '\n' : ' '))
    std::cout << *i;
}

// substitue y for x if x > y.
template <class T> inline bool sbmin(T &x, const T &y) {
  return x > y ? x = y, true : false;
}
// substitue y for x if x < y.
template <class T> inline bool sbmax(T &x, const T &y) {
  return x < y ? x = y, true : false;
}
// binary search.
i64 bin(const std::function<bool(i64)> &pred, i64 ok, i64 ng) {
  while (std::abs(ok - ng) > 1) {
    i64 mid = (ok + ng) / 2;
    (pred(mid) ? ok : ng) = mid;
  }
  return ok;
}
double bin(const std::function<bool(double)> &pred, double ok, double ng,
           const double eps) {
  while (std::abs(ok - ng) > eps) {
    double mid = (ok + ng) / 2;
    (pred(mid) ? ok : ng) = mid;
  }
  return ok;
}
// be careful that val is type-sensitive.
template <class T, class A, size_t N> void init(A (&array)[N], const T &val) {
  std::fill((T *)array, (T *)(array + N), val);
}
// reset all bits.
template <class A> void reset(A &array) { memset(array, 0, sizeof(array)); }

/* The main code follows. */

using namespace std;

int main() {
  void __solve();
  u32 t = 1;
#ifdef LOCAL
  t = 1;
#endif
  // t = -1;
  // cin >> t;
  while (t--) {
    __solve();
  }
}

#ifndef LAZY_SEGMENT_TREE_HPP
#define LAZY_SEGMENT_TREE_HPP

template <class Monoid, class Action> class lazy_segment_tree {
  using value_type = typename Monoid::value_type;
  using operand_type = typename Action::value_type;
  Monoid *const monoid_ptr, &monoid;
  Action *const action_ptr, &action;
  const size_t orig_n, ext_n;
  std::vector<value_type> data;
  std::vector<operand_type> lazy;

  size_t left_node(size_t node) const { return left_node(node); }
  size_t right_node(size_t node) const { return right_node(node); }
  void recalc(size_t node) {
    data[node] = monoid(data[left_node(node)], data[right_node(node)]);
  }

  void update(size_t begin, size_t end, const operand_type &operand,
              size_t node, size_t l, size_t r) {
    if (end <= l || r <= begin)
      return;
    if (begin <= l && r <= end) {
      action.act(data[node], operand);
      if (node < ext_n)
        action(lazy[node], operand);
    } else {
      update(0, ext_n, lazy[node], left_node(node), l, (l + r) >> 1);
      update(0, ext_n, lazy[node], right_node(node), (l + r) >> 1, r);
      lazy[node] = action.identity();
      update(begin, end, operand, left_node(node), l, (l + r) >> 1);
      update(begin, end, operand, right_node(node), (l + r) >> 1, r);
      recalc(node);
    }
  }

  void left_bound(size_t idx,
                  const std::function<bool(const value_type &)> &pred,
                  size_t node, size_t l, size_t r, value_type &now,
                  size_t &res) {
    if (idx <= l || r < res)
      return;
    if (r <= idx) {
      const value_type nxt = monoid(data[node], now);
      if (pred(nxt)) {
        res = l, now = nxt;
        return;
      }
    }
    if (r - l > 1) {
      action(lazy[right_node(node)], lazy[node]);
      action.act(data[right_node(node)], lazy[node]);
      left_bound(idx, pred, right_node(node), (l + r) >> 1, r, now, res);
      action(lazy[left_node(node)], lazy[node]);
      action.act(data[left_node(node)], lazy[node]);
      left_bound(idx, pred, left_node(node), l, (l + r) >> 1, now, res);
      lazy[node] = action.identity();
    }
  }

  void right_bound(size_t idx,
                   const std::function<bool(const value_type &)> &pred,
                   size_t node, size_t l, size_t r, value_type &now,
                   size_t &res) {
    if (idx >= r || l > res)
      return;
    if (l >= idx) {
      const value_type nxt = monoid(now, data[node]);
      if (pred(nxt)) {
        res = r, now = nxt;
        return;
      }
    }
    if (r - l > 1) {
      action(lazy[left_node(node)], lazy[node]);
      action.act(data[left_node(node)], lazy[node]);
      right_bound(idx, pred, left_node(node), l, (l + r) >> 1, now, res);
      action(lazy[right_node(node)], lazy[node]);
      action.act(data[right_node(node)], lazy[node]);
      right_bound(idx, pred, right_node(node), (l + r) >> 1, r, now, res);
      lazy[node] = action.identity();
    }
  }

public:
  explicit lazy_segment_tree(size_t n)
      : monoid_ptr{new Monoid}, monoid{*monoid_ptr},
        action_ptr{new Action}, action{*action_ptr}, orig_n{n},
        ext_n(n > 1 ? 1 << (32 - __builtin_clz(n - 1)) : 1),
        data(ext_n << 1, monoid.identity()), lazy(ext_n, action.identity()) {}
  lazy_segment_tree(size_t n, Monoid &_monoid)
      : monoid_ptr{}, monoid{_monoid},
        action_ptr{new Action}, action{*action_ptr}, orig_n{n},
        ext_n(n > 1 ? 1 << (32 - __builtin_clz(n - 1)) : 1),
        data(ext_n << 1, monoid.identity()), lazy(ext_n, action.identity()) {}
  lazy_segment_tree(size_t n, Action &_actor)
      : monoid_ptr{new Monoid}, monoid{*monoid_ptr},
        action_ptr{}, action{_actor}, orig_n{n},
        ext_n(n > 1 ? 1 << (32 - __builtin_clz(n - 1)) : 1),
        data(ext_n << 1, monoid.identity()), lazy(ext_n, action.identity()) {}
  lazy_segment_tree(size_t n, Monoid &_monoid, Action &_actor)
      : monoid_ptr{}, monoid{_monoid}, action_ptr{}, action{_actor}, orig_n{n},
        ext_n(n > 1 ? 1 << (32 - __builtin_clz(n - 1)) : 1),
        data(ext_n << 1, monoid.identity()), lazy(ext_n, action.identity()) {}
  ~lazy_segment_tree() {
    if (monoid_ptr)
      delete monoid_ptr;
    if (action_ptr)
      delete action_ptr;
  }

  // copy of value at index i.
  value_type operator[](size_t i) { return fold(i, i + 1); }

  void build(value_type *__first, value_type *__last) {
    std::copy(__first, __last, &data[ext_n]);
    for (size_t i = ext_n; i; --i)
      recalc(i);
  }

  template <class iterator> void build(iterator __first, iterator __last) {
    static_assert(
        std::is_same<typename std::iterator_traits<iterator>::value_type,
                     value_type>::value,
        "iterator's value_type should be equal to Monoid's");
    std::copy(__first, __last, &data[ext_n]);
    for (size_t i = ext_n - 1; i; --i)
      recalc(i);
  }

  void init(const value_type &x) {
    for (size_t i = 0; i != ext_n; ++i)
      data[i | ext_n] = x;
    for (size_t i = ext_n - 1; i; --i)
      recalc(i);
  }

  void update(size_t index, const operand_type &operand) {
    update(index, index + 1, operand);
  }

  void update(size_t begin, size_t end, const operand_type &operand) {
    assert(0 <= begin && end <= orig_n);
    update(begin, end, operand, 1, 0, ext_n);
  }

  value_type fold(size_t begin, size_t end) {
    assert(0 <= begin && end <= orig_n);
    value_type left_val{monoid.identity()}, right_val{monoid.identity()};
    size_t l{begin += ext_n}, r{end += ext_n};
    --end;
    while (begin >>= 1, end >>= 1) {
      if (l < r) {
        if (l & 1)
          left_val = monoid(left_val, data[l++]);
        if (r & 1)
          right_val = monoid(data[--r], right_val);
      }
      action.act(left_val, lazy[begin]);
      action.act(right_val, lazy[end]);
      l >>= 1, r >>= 1;
    }
    return monoid(left_val, right_val);
  }

  // minimum l where range [l, index) meets the condition.
  size_t left_bound(size_t index,
                    const std::function<bool(const value_type &)> &pred) {
    assert(index <= orig_n);
    size_t res = index;
    value_type now = monoid.identity();
    left_bound(index, pred, 1, 0, ext_n, now, res);
    return res;
  }

  // maximum r where range [index, r) meets the condition.
  size_t right_bound(size_t index,
                     const std::function<bool(const value_type &)> &pred) {
    assert(index < orig_n);
    size_t res = index;
    value_type now = monoid.identity();
    right_bound(index, pred, 1, 0, ext_n, now, res);
    return res < orig_n ? res : orig_n;
  }
}; // class lazy_segment_tree

#endif

void __solve() {
  int n;
  cin >> n;
  int m;
  cin >> m;
  vector<vector<pii>> fro(n), to(n);
  for (i32 i = 0; i < m; ++i) {
    int l, r, c;
    cin >> l >> r >> c;
    l--;
    r--;
    fro[l].emplace_back(r, c);
    to[r].emplace_back(l, c);
  }

  const i64 inf = 1e18;

  struct mono {
    using value_type = i64;
    i64 operator()(i64 x, i64 y) { return min(x, y); }
    i64 identity() { return inf; }
  };

  struct action {
    using value_type = i64;
    void operator()(i64 &x, i64 y) { x = min(x, y); }
    void act(i64 &x, i64 y) { x = min(x, y); }
    i64 identity() { return inf; }
  };

  lazy_segment_tree<mono, action> seg(n);

  seg.update(0, 0);

  for (i32 i = 0; i < n; ++i) {
    for (auto itv : to[i]) {
      int l, c;
      tie(l, c) = itv;
      seg.update(i, seg.fold(l, i) + c);
    }
    for (auto itv : fro[i]) {
      int r, c;
      tie(r, c) = itv;
      seg.update(i, r + 1, seg[i] + c);
    }
  }

  if (seg[n - 1] != inf) {
    cout << seg[n - 1] << "\n";
  } else {
    cout << -1 << "\n";
  }
}


Fixed submission:
#ifdef LOCAL
#define _GLIBCXX_DEBUG
#define __clock__
#else
#pragma GCC optimize("Ofast")
// #define NDEBUG
#endif
#define __precision__ 10
#define iostream_untie true
#define debug_stream std::cerr

#include <algorithm>
#include <bitset>
#include <cassert>
#include <chrono>
#include <complex>
#include <cstring>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <unordered_map>
#include <unordered_set>

#define all(v) std::begin(v), std::end(v)
#define rall(v) std::rbegin(v), std::rend(v)
#define odd(n) ((n)&1)
#define even(n) (not __odd(n))
#define __popcount(n) __builtin_popcountll(n)
#define __clz32(n) __builtin_clz(n)
#define __clz64(n) __builtin_clzll(n)
#define __ctz32(n) __builtin_ctz(n)
#define __ctz64(n) __builtin_ctzll(n)

using i32 = int_least32_t;
using i64 = int_least64_t;
using u32 = uint_least32_t;
using u64 = uint_least64_t;
using pii = std::pair<i32, i32>;
using pll = std::pair<i64, i64>;
template <class T> using heap = std::priority_queue<T>;
template <class T>
using rheap = std::priority_queue<T, std::vector<T>, std::greater<T>>;
template <class K, class T> using hashmap = std::unordered_map<K, T>;
template <class T> using hashset = std::unordered_set<T>;

namespace execution {
using namespace std::chrono;
system_clock::time_point start_time, end_time;
long long get_elapsed_time() {
  end_time = system_clock::now();
  return duration_cast<milliseconds>(end_time - start_time).count();
}
void print_elapsed_time() {
  std::cerr << "\n----- Exec time : " << get_elapsed_time() << " ms -----\n\n";
}
struct setupper {
  setupper() {
    if (iostream_untie)
      std::ios::sync_with_stdio(false), std::cin.tie(nullptr);
    std::cout << std::fixed << std::setprecision(__precision__);
#ifdef stderr_path
    if (freopen(stderr_path, "a", stderr)) {
      std::cerr << std::fixed << std::setprecision(__precision__);
    }
#endif
#ifdef stdout_path
    if (not freopen(stdout_path, "w", stdout)) {
      freopen("CON", "w", stdout);
      std::cerr << "Failed to open the stdout file\n\n";
    }
    std::cout << "";
#endif
#ifdef stdin_path
    if (not freopen(stdin_path, "r", stdin)) {
      freopen("CON", "r", stdin);
      std::cerr << "Failed to open the stdin file\n\n";
    }
#endif
#ifdef LOCAL
    std::cerr << "----- stderr at LOCAL -----\n\n";
    atexit(print_elapsed_time);
#else
    fclose(stderr);
#endif
#ifdef __clock__
    start_time = system_clock::now();
#endif
  }
} __setupper;
class myclock_t {
  system_clock::time_point built_pt, last_pt;
  int built_ln, last_ln;
  std::string built_func, last_func;
  bool is_built;

public:
  myclock_t() : is_built(false) {}
  void build(int crt_ln, const std::string &crt_func) {
    is_built = true, last_pt = built_pt = system_clock::now(),
    last_ln = built_ln = crt_ln, last_func = built_func = crt_func;
  }
  void set(int crt_ln, const std::string &crt_func) {
    if (is_built)
      last_pt = system_clock::now(), last_ln = crt_ln, last_func = crt_func;
    else
      debug_stream << "[ " << crt_ln << " : " << crt_func << " ] "
                   << "myclock_t::set failed (yet to be built!)\n";
  }
  void get(int crt_ln, const std::string &crt_func) {
    if (is_built) {
      system_clock::time_point crt_pt(system_clock::now());
      long long diff = duration_cast<milliseconds>(crt_pt - last_pt).count();
      debug_stream << diff << " ms elapsed from"
                   << " [ " << last_ln << " : " << last_func << " ]";
      if (last_ln == built_ln)
        debug_stream << " (when built)";
      debug_stream << " to"
                   << " [ " << crt_ln << " : " << crt_func << " ]"
                   << "\n";
      last_pt = built_pt, last_ln = built_ln, last_func = built_func;
    } else {
      debug_stream << "[ " << crt_ln << " : " << crt_func << " ] "
                   << "myclock_t::get failed (yet to be built!)\n";
    }
  }
};
} // namespace execution

#ifdef __clock__
execution::myclock_t __myclock;
#define build_clock() __myclock.build(__LINE__, __func__)
#define set_clock() __myclock.set(__LINE__, __func__)
#define get_clock() __myclock.get(__LINE__, __func__)
#else
#define build_clock() ((void)0)
#define set_clock() ((void)0)
#define get_clock() ((void)0)
#endif

namespace std {
template <class P> void rsort(P __first, P __last) {
  sort(__first, __last, greater<>());
}
template <class T> size_t hash_combine(size_t seed, T const &key) {
  return seed ^ (hash<T>()(key) + 0x9e3779b9 + (seed << 6) + (seed >> 2));
}
template <class T, class U> struct hash<pair<T, U>> {
  size_t operator()(pair<T, U> const &pr) const {
    return hash_combine(hash_combine(0, pr.first), pr.second);
  }
};
template <class tuple_t, size_t index = tuple_size<tuple_t>::value - 1>
struct tuple_hash_calc {
  static size_t apply(size_t seed, tuple_t const &t) {
    return hash_combine(tuple_hash_calc<tuple_t, index - 1>::apply(seed, t),
                        get<index>(t));
  }
};
template <class tuple_t> struct tuple_hash_calc<tuple_t, 0> {
  static size_t apply(size_t seed, tuple_t const &t) {
    return hash_combine(seed, get<0>(t));
  }
};
template <class... T> struct hash<tuple<T...>> {
  size_t operator()(tuple<T...> const &t) const {
    return tuple_hash_calc<tuple<T...>>::apply(0, t);
  }
};
template <class T, class U>
istream &operator>>(std::istream &s, pair<T, U> &p) {
  return s >> p.first >> p.second;
}
template <class T, class U>
ostream &operator<<(std::ostream &s, const pair<T, U> &p) {
  return s << p.first << " " << p.second;
}
template <class T> istream &operator>>(istream &s, vector<T> &v) {
  for (T &e : v)
    s >> e;
  return s;
}
template <class T> ostream &operator<<(ostream &s, const vector<T> &v) {
  bool is_front = true;
  for (const T &e : v) {
    if (not is_front)
      s << ' ';
    else
      is_front = false;
    s << e;
  }
  return s;
}
template <class tuple_t, size_t index> struct tupleos {
  static ostream &apply(ostream &s, const tuple_t &t) {
    tupleos<tuple_t, index - 1>::apply(s, t);
    return s << " " << get<index>(t);
  }
};
template <class tuple_t> struct tupleos<tuple_t, 0> {
  static ostream &apply(ostream &s, const tuple_t &t) { return s << get<0>(t); }
};
template <class... T> ostream &operator<<(ostream &s, const tuple<T...> &t) {
  return tupleos<tuple<T...>, tuple_size<tuple<T...>>::value - 1>::apply(s, t);
}
template <> ostream &operator<<(ostream &s, const tuple<> &t) { return s; }
string revstr(string str) {
  reverse(str.begin(), str.end());
  return str;
}
} // namespace std

#ifdef LOCAL
#define dump(...)                                                              \
  debug_stream << "[ " << __LINE__ << " : " << __FUNCTION__ << " ]\n",         \
      dump_func(#__VA_ARGS__, __VA_ARGS__)
template <class T> void dump_func(const char *ptr, const T &x) {
  debug_stream << '\t';
  for (char c = *ptr; c != '\0'; c = *++ptr)
    if (c != ' ')
      debug_stream << c;
  debug_stream << " : " << x << '\n';
}
template <class T, class... rest_t>
void dump_func(const char *ptr, const T &x, rest_t... rest) {
  debug_stream << '\t';
  for (char c = *ptr; c != ','; c = *++ptr)
    if (c != ' ')
      debug_stream << c;
  debug_stream << " : " << x << ",\n";
  dump_func(++ptr, rest...);
}
#else
#define dump(...) ((void)0)
#endif
template <class P> void read_range(P __first, P __second) {
  for (P i = __first; i != __second; ++i)
    std::cin >> *i;
}
template <class P> void write_range(P __first, P __second) {
  for (P i = __first; i != __second;
       std::cout << (++i == __second ? '\n' : ' '))
    std::cout << *i;
}

// substitue y for x if x > y.
template <class T> inline bool sbmin(T &x, const T &y) {
  return x > y ? x = y, true : false;
}
// substitue y for x if x < y.
template <class T> inline bool sbmax(T &x, const T &y) {
  return x < y ? x = y, true : false;
}
// binary search.
i64 bin(const std::function<bool(i64)> &pred, i64 ok, i64 ng) {
  while (std::abs(ok - ng) > 1) {
    i64 mid = (ok + ng) / 2;
    (pred(mid) ? ok : ng) = mid;
  }
  return ok;
}
double bin(const std::function<bool(double)> &pred, double ok, double ng,
           const double eps) {
  while (std::abs(ok - ng) > eps) {
    double mid = (ok + ng) / 2;
    (pred(mid) ? ok : ng) = mid;
  }
  return ok;
}
// be careful that val is type-sensitive.
template <class T, class A, size_t N> void init(A (&array)[N], const T &val) {
  std::fill((T *)array, (T *)(array + N), val);
}
// reset all bits.
template <class A> void reset(A &array) { memset(array, 0, sizeof(array)); }

/* The main code follows. */

using namespace std;

int main() {
  void __solve();
  u32 t = 1;
#ifdef LOCAL
  t = 1;
#endif
  // t = -1;
  // cin >> t;
  while (t--) {
    __solve();
  }
}

#ifndef LAZY_SEGMENT_TREE_HPP
#define LAZY_SEGMENT_TREE_HPP

template <class Monoid, class Action> class lazy_segment_tree {
  using value_type = typename Monoid::value_type;
  using operand_type = typename Action::value_type;
  Monoid *const monoid_ptr, &monoid;
  Action *const action_ptr, &action;
  const size_t orig_n, ext_n;
  std::vector<value_type> data;
  std::vector<operand_type> lazy;

  size_t left_node(size_t node) const { return node << 1; }
  size_t right_node(size_t node) const { return node << 1 | 1; }
  void recalc(size_t node) {
    data[node] = monoid(data[left_node(node)], data[right_node(node)]);
  }

  void update(size_t begin, size_t end, const operand_type &operand,
              size_t node, size_t l, size_t r) {
    if (end <= l || r <= begin)
      return;
    if (begin <= l && r <= end) {
      action.act(data[node], operand);
      if (node < ext_n)
        action(lazy[node], operand);
    } else {
      update(0, ext_n, lazy[node], left_node(node), l, (l + r) >> 1);
      update(0, ext_n, lazy[node], right_node(node), (l + r) >> 1, r);
      lazy[node] = action.identity();
      update(begin, end, operand, left_node(node), l, (l + r) >> 1);
      update(begin, end, operand, right_node(node), (l + r) >> 1, r);
      recalc(node);
    }
  }

  void left_bound(size_t idx,
                  const std::function<bool(const value_type &)> &pred,
                  size_t node, size_t l, size_t r, value_type &now,
                  size_t &res) {
    if (idx <= l || r < res)
      return;
    if (r <= idx) {
      const value_type nxt = monoid(data[node], now);
      if (pred(nxt)) {
        res = l, now = nxt;
        return;
      }
    }
    if (r - l > 1) {
      action(lazy[right_node(node)], lazy[node]);
      action.act(data[right_node(node)], lazy[node]);
      left_bound(idx, pred, right_node(node), (l + r) >> 1, r, now, res);
      action(lazy[left_node(node)], lazy[node]);
      action.act(data[left_node(node)], lazy[node]);
      left_bound(idx, pred, left_node(node), l, (l + r) >> 1, now, res);
      lazy[node] = action.identity();
    }
  }

  void right_bound(size_t idx,
                   const std::function<bool(const value_type &)> &pred,
                   size_t node, size_t l, size_t r, value_type &now,
                   size_t &res) {
    if (idx >= r || l > res)
      return;
    if (l >= idx) {
      const value_type nxt = monoid(now, data[node]);
      if (pred(nxt)) {
        res = r, now = nxt;
        return;
      }
    }
    if (r - l > 1) {
      action(lazy[left_node(node)], lazy[node]);
      action.act(data[left_node(node)], lazy[node]);
      right_bound(idx, pred, left_node(node), l, (l + r) >> 1, now, res);
      action(lazy[right_node(node)], lazy[node]);
      action.act(data[right_node(node)], lazy[node]);
      right_bound(idx, pred, right_node(node), (l + r) >> 1, r, now, res);
      lazy[node] = action.identity();
    }
  }

public:
  explicit lazy_segment_tree(size_t n)
      : monoid_ptr{new Monoid}, monoid{*monoid_ptr},
        action_ptr{new Action}, action{*action_ptr}, orig_n{n},
        ext_n(n > 1 ? 1 << (32 - __builtin_clz(n - 1)) : 1),
        data(ext_n << 1, monoid.identity()), lazy(ext_n, action.identity()) {}
  lazy_segment_tree(size_t n, Monoid &_monoid)
      : monoid_ptr{}, monoid{_monoid},
        action_ptr{new Action}, action{*action_ptr}, orig_n{n},
        ext_n(n > 1 ? 1 << (32 - __builtin_clz(n - 1)) : 1),
        data(ext_n << 1, monoid.identity()), lazy(ext_n, action.identity()) {}
  lazy_segment_tree(size_t n, Action &_actor)
      : monoid_ptr{new Monoid}, monoid{*monoid_ptr},
        action_ptr{}, action{_actor}, orig_n{n},
        ext_n(n > 1 ? 1 << (32 - __builtin_clz(n - 1)) : 1),
        data(ext_n << 1, monoid.identity()), lazy(ext_n, action.identity()) {}
  lazy_segment_tree(size_t n, Monoid &_monoid, Action &_actor)
      : monoid_ptr{}, monoid{_monoid}, action_ptr{}, action{_actor}, orig_n{n},
        ext_n(n > 1 ? 1 << (32 - __builtin_clz(n - 1)) : 1),
        data(ext_n << 1, monoid.identity()), lazy(ext_n, action.identity()) {}
  ~lazy_segment_tree() {
    if (monoid_ptr)
      delete monoid_ptr;
    if (action_ptr)
      delete action_ptr;
  }

  // copy of value at index i.
  value_type operator[](size_t i) { return fold(i, i + 1); }

  void build(value_type *__first, value_type *__last) {
    std::copy(__first, __last, &data[ext_n]);
    for (size_t i = ext_n; i; --i)
      recalc(i);
  }

  template <class iterator> void build(iterator __first, iterator __last) {
    static_assert(
        std::is_same<typename std::iterator_traits<iterator>::value_type,
                     value_type>::value,
        "iterator's value_type should be equal to Monoid's");
    std::copy(__first, __last, &data[ext_n]);
    for (size_t i = ext_n - 1; i; --i)
      recalc(i);
  }

  void init(const value_type &x) {
    for (size_t i = 0; i != ext_n; ++i)
      data[i | ext_n] = x;
    for (size_t i = ext_n - 1; i; --i)
      recalc(i);
  }

  void update(size_t index, const operand_type &operand) {
    update(index, index + 1, operand);
  }

  void update(size_t begin, size_t end, const operand_type &operand) {
    assert(0 <= begin && end <= orig_n);
    update(begin, end, operand, 1, 0, ext_n);
  }

  value_type fold(size_t begin, size_t end) {
    assert(0 <= begin && end <= orig_n);
    value_type left_val{monoid.identity()}, right_val{monoid.identity()};
    size_t l{begin += ext_n}, r{end += ext_n};
    --end;
    while (begin >>= 1, end >>= 1) {
      if (l < r) {
        if (l & 1)
          left_val = monoid(left_val, data[l++]);
        if (r & 1)
          right_val = monoid(data[--r], right_val);
      }
      action.act(left_val, lazy[begin]);
      action.act(right_val, lazy[end]);
      l >>= 1, r >>= 1;
    }
    return monoid(left_val, right_val);
  }

  // minimum l where range [l, index) meets the condition.
  size_t left_bound(size_t index,
                    const std::function<bool(const value_type &)> &pred) {
    assert(index <= orig_n);
    size_t res = index;
    value_type now = monoid.identity();
    left_bound(index, pred, 1, 0, ext_n, now, res);
    return res;
  }

  // maximum r where range [index, r) meets the condition.
  size_t right_bound(size_t index,
                     const std::function<bool(const value_type &)> &pred) {
    assert(index < orig_n);
    size_t res = index;
    value_type now = monoid.identity();
    right_bound(index, pred, 1, 0, ext_n, now, res);
    return res < orig_n ? res : orig_n;
  }
}; // class lazy_segment_tree

#endif

void __solve() {
  int n;
  cin >> n;
  int m;
  cin >> m;
  vector<vector<pii>> fro(n), to(n);
  for (i32 i = 0; i < m; ++i) {
    int l, r, c;
    cin >> l >> r >> c;
    l--;
    r--;
    fro[l].emplace_back(r, c);
    to[r].emplace_back(l, c);
  }

  const i64 inf = 1e18;

  struct mono {
    using value_type = i64;
    i64 operator()(i64 x, i64 y) { return min(x, y); }
    i64 identity() { return inf; }
  };

  struct action {
    using value_type = i64;
    void operator()(i64 &x, i64 y) { x = min(x, y); }
    void act(i64 &x, i64 y) { x = min(x, y); }
    i64 identity() { return inf; }
  };

  lazy_segment_tree<mono, action> seg(n);

  seg.update(0, 0);

  for (i32 i = 0; i < n; ++i) {
    for (auto itv : to[i]) {
      int l, c;
      tie(l, c) = itv;
      seg.update(i, seg.fold(l, i) + c);
    }
    for (auto itv : fro[i]) {
      int r, c;
      tie(r, c) = itv;
      seg.update(i, r + 1, seg[i] + c);
    }
  }

  if (seg[n - 1] != inf) {
    cout << seg[n - 1] << "\n";
  } else {
    cout << -1 << "\n";
  }
}