#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using db = double;
using ld = long double;
#define fs first
#define sc second
#define pb push_back
#define mp make_pair
#define mt make_tuple
#define eb emplace_back
#define all(v) (v).begin(),(v).end()
#define siz(v) (ll)(v).size()
#define rep(i,a,n) for(ll i=a;i<(ll)(n);i++)
#define repr(i,a,n) for(ll i=n-1;(ll)a<=i;i--)
#define lb lower_bound
#define ub upper_bound
typedef pair<int,int> P;
typedef pair<ll,ll> PL;
const ll mod = 1000000007;
const ll INF = 1000000099;
const ll LINF = (ll)(1e18 +99);
vector<ll> dx={-1,1,0,0},dy={0,0,-1,1};
template<typename T,typename U> void chmin(T& t, const U& u){if(t>u)t=u;}
template<typename T,typename U> void chmax(T& t, const U& u){if(t<u)t=u;}
template<typename T>T gcd(T a,T b){return b?gcd(b,a%b):a;}
template<typename T>T mpow(T a, T n) {
   T res = 1;
   for(;n;n>>=1) {
      if (n & 1) res = res * a;
      a = a * a;
   }
   return res;
}

//cin.tie(0);ios::sync_with_stdio(false);
//cout<<fixed<<setprecision(20);

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

//cin.tie(0);ios::sync_with_stdio(false);
//cout<<fixed<<setprecision(20);


template<typename T,T(F_dd)(T,T),T(F_dl)(T,T),T(F_ll)(T,T)>
//dat-dat dat-lazy lazy-lazy min,add,addなどを入れる
struct Lazysegtree{
    int sz,ex;
    T ini_d,ini_l;//default値
    vector<T> dat,laz;
    vector<bool> need;

    Lazysegtree(int n,T _ini_d,T _ini_l) : Lazysegtree(vector<T>(n,_ini_d),_ini_d,_ini_l){}
    Lazysegtree(vector<T> init,T _ini_d, T _ini_l) : ini_d(_ini_d),ini_l(_ini_l){
        int n=(int)(init.size());
        ex=1;
        while((1<<ex) < n)ex++;
        sz=(1<<ex);//最下層のノード数になる
        
        dat=vector<T>(2*sz-1,ini_d);
        laz=vector<T>(2*sz-1,ini_l);
        need=vector<bool>(2*sz-1,false);
        for (int i = 0; i < n; i++) dat[sz + i -1] = init[i];//最下層以外のノード数はsz-1
        for (int i = sz-2; i >= 0; i--) {
            update(i);
        }//上層のノードの初期化
    }

    void update(int k){dat[k]=F_dd(dat[2*k+1],dat[2*k+2]);}//上層ノードの更新

    void seg_upd(int k,T x){//区間ノードに対する更新
        dat[k] = F_dl(dat[k],x);
        laz[k] = F_ll(laz[k],x);
        need[k]=true;
    }

    void eval(int k){//子の区間に伝播させる
        if(!need[k])return;

        seg_upd(2*k+1,laz[k]);
        seg_upd(2*k+2,laz[k]);
        laz[k]=ini_l;
        need[k]=false;
    }

    //区間[a,b)に対する取得クエリ [l,r)はノード番号kに対応する区間
    T get_q(int a,int b,int l,int r,int k){
        if(b<=l || r<=a) return ini_d;
        if(a<=l && r<=b) return dat[k];
        eval(k);//ノードを見たので遅延を一段階伝播させておく
        return F_dd(get_q(a,b,l,(l+r)/2,2*k+1),get_q(a,b,(l+r)/2,r,2*k+2));
    }
    T get_q(int a,int b){return get_q(a,b,0,sz,0);}


    //区間[a,b)に対する更新クエリ
    void up_q(int a,int b,T x,int l,int r,int k){
        if(b<=l || r<=a) return;
        if(a<=l && r<=b){
            seg_upd(k,x);
            return;
        }

        //子ノードを見る必要がある場合
        eval(k);
        up_q(a,b,x,l,(l+r)/2,2*k+1);
        up_q(a,b,x,(l+r)/2,r,2*k+2);
        update(k);//更新終了後、親も更新
    }
    void up_q(int a,int b,T x){up_q(a,b,x,0,sz,0);}
};


ll my_min(ll a,ll b){return min(a,b);}
//ll my_replace(ll a,ll b){return b;}

struct edge{
    ll l,r,cost;
};

bool comp(const edge a,const edge b){
    return a.l<b.l;
}

signed main(){
    ll n,m;cin>>n>>m;
    vector<edge> v(m);
    rep(i,0,m){
        cin>>v[i].l>>v[i].r>>v[i].cost;
        v[i].l--;v[i].r--;
    }

    sort(all(v),comp);

    Lazysegtree<ll,my_min,my_min,my_min> seg(n,LINF,LINF);
    seg.up_q(0,1,0);

    rep(i,0,m){
        ll next=seg.get_q(v[i].l,v[i].l+1)+v[i].cost;
        seg.up_q(v[i].l+1,v[i].r+1,next);
    }

    ll ans=seg.get_q(n-1,n);
    if(ans>=LINF){
        cout<<-1<<endl;
    }else{
        cout<<ans<<endl;
    }

}


//( ・ __ ・ ) KEEP BEING ORGANIZED
//CHECK overflow,vector_size,output_format?

Measured memory_bytes: 7424