//https://lorent-kyopro.hatenablog.com/entry/2020/07/24/170656
#pragma GCC optimize("O3")
#include <bits/stdc++.h>
#define ll long long
#define rep(i,n) for(ll i=0;i<(n);i++)
#define pll pair<ll,ll>
#define pii pair<int,int>
#define pq priority_queue
#define pb push_back
#define eb emplace_back
#define fi first
#define se second
#define endl '\n'
#define ios ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
#define lb(c,x) distance(c.begin(),lower_bound(all(c),x))
#define ub(c,x) distance(c.begin(),upper_bound(all(c),x))

using namespace std;

template<class T> inline bool chmax(T& a,T b){if(a<b){a=b;return 1;}return 0;}
template<class T> inline bool chmin(T& a,T b){if(a>b){a=b;return 1;}return 0;}

using namespace std;

struct range_edge_graph {
    int n;
    struct edge { int to; long long weight;};
    vector<vector<edge>> g;
    
    range_edge_graph(int n) : n(n) {

        // 1つのセグ木のサイズがn<<1
        // 2つのセグ木をもつのでn<<2
        g.resize(n<<2);

        // 辺を張る

        // まずは各セグ木内の辺から
        for (int i = 1; i < n; ++i) {

            // c1は左の子の番号, c2は右の子の番号
            int c1 = i<<1|0, c2 = i<<1|1;

            // 上のセグ木には根→葉方向に重み0の辺を張る
            g[i].push_back({c1, 0});
            g[i].push_back({c2, 0});

            // 下のセグ木には葉→根方向に重み0の辺を張る
            // 下のセグ木を操作したいときは +2*n すればよい
            g[c1+2*n].push_back({i+2*n, 0});
            g[c2+2*n].push_back({i+2*n, 0});
        }

        // 上のセグ木と下のセグ木の向かい合う葉同士に重み0の辺を張る
        for (int i = n; i < 2*n; ++i) g[i].push_back({i+2*n, 0});
    }
    // from [l1, r1) to [l2, r2)
    void add_edge(int l1, int r1, int l2, int r2, long long w) {

        // 下のセグ木から上のセグ木に向けて辺を持つノードを追加する

        // 追加するノードの番号
        int id = g.size();

        // 下のセグ木の[l1, r1)に対応するノード → 追加するノード  に重み0の辺を張る
        for (l1 += n, r1 += n; l1 < r1; l1 >>= 1, r1 >>= 1) {
            if (l1 & 1) g[l1+2*n].push_back({id, 0}), l1++;
            if (r1 & 1) --r1, g[r1+2*n].push_back({id, 0});
        }
    
        // 追加するノードの隣接リスト 
        vector<edge> node;

        // 追加するノード → 上のセグ木の[l2, r2)に対応するノード  に重みwの辺を張る
        for (l2 += n, r2 += n; l2 < r2; l2 >>= 1, r2 >>= 1) {
            if (l2 & 1) node.push_back({l2++, w});
            if (r2 & 1) node.push_back({--r2, w});
        }

        // ノードを追加
        g.push_back(node);
    }
    
    vector<long long> dijkstra(int s) {
        s += n;
        vector<long long> dist(g.size(), numeric_limits<long long>::max());
        dist[s] = 0;
        using P = pair<long long, long long>;
        priority_queue<P, vector<P>, greater<P>> que;
        que.emplace(0, s);
        while (!que.empty()) {
            P p = que.top();
            que.pop();
            int v = p.second;
            if (dist[v] < p.first) continue;
            for (edge& e : g[v]) {
                if (dist[e.to] > dist[v] + e.weight) {
                    dist[e.to] = dist[v] + e.weight;
                    que.emplace(dist[e.to], e.to);
                }
            }
        }
        vector<long long> res(dist.begin() + n, dist.begin() + 2*n);
        return res;
    }
};

//https://atcoder.jp/contests/nikkei2019-2-qual/tasks/nikkei2019_2_qual_d
//使用例

int main() {
    
 
    int n, m;
    cin >> n >> m;
    range_edge_graph g(n);
 
    for (int i = 0; i < m; ++i) {
        int l, r, c;
        cin >> l >> r >> c;
        l--; r--;
        g.add_edge(l, r+1, l, r+1, c);
    }
    auto dist = g.dijkstra(0);
    long long ans = dist[n-1];
    cout << (ans == numeric_limits<long long>::max() ? -1 : ans) << endl;
}

Measured memory_bytes: 89596