#include <algorithm>
#include <cassert>
#include <cfloat>
#include <climits>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <deque>
#include <iostream>
#include <iterator>
#include <limits>
#include <map>
#include <numeric>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

#define FOR(i,k,n) for(int(i)=(k);(i)<(n);++(i))
#define rep(i,n) FOR(i,0,n)
#define all(v) begin(v),end(v)
#define debug(x) std::cerr<<#x<<": "<<x<<"\n"
#define debug2(x,y) std::cerr<<#x<<": "<<x<<", "<<#y<<": "<<y<<"\n"
#define debug3(x,y,z) std::cerr<<#x<<": "<<x<<", "<<#y<<": "<<y<<", "<<#z<<": "<<z<<"\n"

using ll=long long;
using vi=std::vector<int>;
using vvi=std::vector<vi>;
using vll=std::vector<ll>;
using vvll=std::vector<vll>;
template<typename T> using vvec=std::vector<std::vector<T>>;
template<typename T>
auto make_v(size_t sz){return std::vector<T>(sz);}
template<typename T,typename... Ts>
auto make_v(size_t sz,Ts...ts){return std::vector<decltype(make_v<T>(ts...))>(sz,make_v<T>(ts...));}
template<typename T>
void fill_v(T&var,const T&x){var=x;}
template<typename V,typename T>
void fill_v(V&v,const T&x){for(auto&& w:v){fill_v(w,x);}}

template<typename T> std::ostream& operator<<(std::ostream&s,const std::vector<T>&v){
  int sz=v.size();s<<"\n";rep(i,sz){s<<v[i];if(i<sz-1){s<<"\t";}}s<<"\n";return s;}
template<typename T> std::ostream& operator<<(std::ostream&s,const std::vector<std::vector<T>>&v){
  for(auto&& w:v){s<<w;}return s;}
template<typename T> std::ostream& operator<<(std::ostream&s,const std::deque<T>&v){
  int sz=v.size();s<<"\n";rep(i,sz){s<<v[i];if(i<sz-1){s<<"\t";}}s<<"\n";return s;}
template<typename T> std::ostream& operator<<(std::ostream&s,const std::deque<std::deque<T>>&v){
  for(auto&& w:v){s<<w;}return s;}
template<typename T> std::ostream& operator<<(std::ostream&s, const std::set<T>&v){
  s<<"\n";for(auto&& elm:v){s<<elm<<"\t";}s<<"\n";return s;}

inline void scan(int&a){scanf("%d",&a);}
inline void scan(ll&a){scanf("%lld",&a);}
inline void scan(char&a){scanf(" %c",&a);}
inline void scan(double&a){scanf("%lf",&a);}
inline void scan(std::string&s){char BUF[3000000];scanf(" %s",BUF);s=std::string(BUF);}
template<typename T>
inline void scan(std::vector<T>&v){for(auto&& sv:v){scan(sv);}}
template<typename First,typename...Args>
inline void scan(First&f,Args&...args){scan(f);scan(args...);}
inline void print(int a){printf("%d\n",a);}
inline void print(ll a){printf("%lld\n",a);}
inline void print(double a){printf("%.12f\n",a);}
inline void print(std::string s){std::cout<<s<<"\n";}

using namespace std;

ll INF = 1e16;

struct Monoid {
  using T = ll; // type or class of monoid
  static T operate(const T& left, const T& right) {
    return min(left, right); // definition of operator
  }
  static constexpr T identity() { return T(1e16); } // 単位元
};

// モノイド作用
struct M_act {
  using T = ll; // 作用を受ける側の集合の型
  using OperatorMonoid = Monoid;
  static T act(const OperatorMonoid::T& m, const T& a) { return min(m, a); }
};

template<class M_act>
class SegTree {
private:
  using T = typename M_act::T; // 作用を受ける側の集合の型 注意:これは演算される対象を意味する
  using OM = typename M_act::OperatorMonoid;
  using M = typename OM::T; // 作用素モノイドの台集合 注意:これはあくまで演算子、つまり作用する側を意味する
  const int n, h;
  std::vector<T> uv; // underlying values
  std::vector<M> deferred_action; // act(作用)させるべきoperatorを持っている

  void propagate(const M& m, int i) {
    if (i < n) deferred_action[i] = OM::operate(m, deferred_action[i]); // if not leaves, unite actions
    else {
      i -= n;
      uv[i] = M_act::act(m, uv[i]); // if leaves, act immediately
    }
  }

  void propagate_from(int i) {
    if (deferred_action[i] == OM::identity()) { return; }
    propagate(deferred_action[i], i << 1);
    propagate(deferred_action[i], i << 1 | 1);
    deferred_action[i] = OM::identity();
  }

  void propagate_to_uv(int i) {
    i += n;
    for (int j = h; j > 0; --j) propagate_from(i >> j);
  }

  int lg(int n_) {
    n_ -= 1;
    int h_ = 0;
    while (n_ >> h_) ++h_;
    return h_;
  }

public:
  SegTree(int n_, const T& x) : n(n_), h(lg(n)), uv(n, x), deferred_action(n, OM::identity()) {}
  SegTree(const std::vector<T>& v) : n(v.size()), h(lg(n)), uv(v), deferred_action(n, OM::identity()) {}
  template<class Itr>
  SegTree(Itr first, Itr last) : n(std::distance(first, last)), h(lg(n)), uv(first, last), deferred_action(n, OM::identity()) {}

  void act(int l, int r, const M& m) {
    propagate_to_uv(l);
    propagate_to_uv(r-1);
    l += n, r += n;
    for ( ; l < r; l >>= 1, r >>= 1) {
      if (l & 1) propagate(m, l++);
      if (r & 1) propagate(m, r-1);
    }
  }

  void propagate_all() {
    for (int i = 1; i < n; ++i) propagate_from(i);
  }

  void set(int i, const T& x) {
    propagate_to_uv(i);
    uv[i] = x;
  }

  T get(int i) {
    T ret = uv[i];
    i += n;
    while (i >>= 1) ret = M_act::act(deferred_action[i], ret);
    return ret;
  }
};

struct State {
  int left, right;
};

int main() {
  int n, m;
  scan(n, m);
  vvll lrc(m, vll(3));
  rep (i, m) {
    scan(lrc[i]);
    lrc[i][0] -= 1;
    lrc[i][1] -= 1;
  }
  sort(all(lrc));

  vll dp(n, INF);
  dp[0] = 0;

  auto segt = SegTree<M_act>(n, INF);
  segt.set(0, 0);
  rep (i, m) {
    ll l = lrc[i][0];
    ll r = lrc[i][1];
    ll c = lrc[i][2];
    ll base = segt.get(l);
    segt.act(l, r+1, base + c);
  }
  ll ans = segt.get(n-1);
  if (ans == INF) {
    ans = -1;
  }
  print(ans);


  /*
  deque<State> states;
  states.push_back(State{-1, 0});
  while (!states.empty()) {
    auto state = states.front();
    states.pop_front();
    int left = state.left;
    int right = state.right;
    auto lp = upper_bound(all(lrc), (vll){left, INF, INF}) - begin(lrc);
    auto rp = upper_bound(all(lrc), (vll){right, INF, INF}) - begin(lrc);
    debug2(lp, rp);
    FOR (i, lp, rp) {
    }
  }
  */

  return 0;
}


Measured memory_bytes: 7936