#include <iostream>
#include <algorithm>
#include <vector>
#include <limits>
#include <functional>

template <class Data, class Operator>
class LazySegmentTree {
    using DataMerger = std::function<Data(Data, Data)>;
    using OperatorMerger = std::function<Operator(Operator, Operator)>;
    using Applier = std::function<Data(Data, Operator, int)>;

private:
    int length;
    std::vector<Data> dat;
    std::vector<Operator> ope;
    Data dat_id;            // データの単位元
    Operator ope_id;        // 作用素の単位元
    DataMerger dmerge;      // データをマージする関数
    OperatorMerger omerge;  // 作用素をマージする関数
    Applier app;            // データに作用素を適用する関数 第三引数に区間長を取る

    void eval(int nidx, int len) {
        if (ope[nidx] == ope_id) return;
        // 子に作用素を伝播
        if (nidx * 2 + 1 < length * 2) {
            ope[nidx * 2] = omerge(ope[nidx * 2], ope[nidx]);
            ope[nidx * 2 + 1] = omerge(ope[nidx * 2 + 1], ope[nidx]);
        }
        // 値に作用素を反映
        dat[nidx] = app(dat[nidx], ope[nidx], len);
        ope[nidx] = ope_id;
    }

    Data update(int ql, int qr, Operator e, int nidx, int nl, int nr) {
        eval(nidx, nr - nl);
        if (nr <= ql || qr <= nl) return dat[nidx];
        if (ql <= nl && nr <= qr) {
            ope[nidx] = omerge(ope[nidx], e);
            return app(dat[nidx], ope[nidx], nr - nl);
        }
        // 子を再帰的に更新
        Data vl = update(ql, qr, e, nidx * 2, nl, (nl + nr) / 2);
        Data vr = update(ql, qr, e, nidx * 2 + 1, (nl + nr) / 2, nr);
        // 子の更新後から値を更新
        return dat[nidx] = dmerge(vl, vr);
    }

    Data query(int ql, int qr, int nidx, int nl, int nr) {
        eval(nidx, nr - nl);
        if (nr <= ql || qr <= nl) return dat_id;
        if (ql <= nl && nr <= qr) return dat[nidx];
        Data vl = query(ql, qr, nidx * 2, nl, (nl + nr) / 2);
        Data vr = query(ql, qr, nidx * 2 + 1, (nl + nr) / 2, nr);
        return dmerge(vl, vr);
    }

public:
    explicit LazySegmentTree(int N, Data dat_id, Operator ope_id, DataMerger dmerge, OperatorMerger omerge, Applier app)
        : length(1), dat_id(dat_id), ope_id(ope_id), dmerge(dmerge), omerge(omerge), app(app) {
        while (length < N) length *= 2;
        dat.assign(length * 2, dat_id);
        ope.assign(length * 2, ope_id);
    }

    // half-open interval [ql, qr)
    Data update(int ql, int qr, Operator e) { return update(ql, qr, e, 1, 0, length); }

    // half-open interval [ql, qr)
    Data query(int ql, int qr) { return query(ql, qr, 1, 0, length); }
};

using lint = long long;
constexpr lint INF = std::numeric_limits<lint>::max() / 3;

struct Seg {
    int l, r;
    lint c;
};

int main() {
    int n, m;
    std::cin >> n >> m;

    std::vector<Seg> segs(m);
    for (auto& s : segs) {
        std::cin >> s.l >> s.r >> s.c;
        --s.l, --s.r;
    }

    // 終端でソート
    std::sort(segs.begin(), segs.end(),
              [](Seg a, Seg b) { return a.r < b.r; });

    LazySegmentTree<lint, lint> seg(
        n, INF, INF,
        [](lint a, lint b) { return std::min(a, b); },
        [](lint e, lint f) { return std::min(e, f); },
        [](lint a, lint e, int k) { return std::min(a, e); });
    seg.update(0, 1, 0);

    for (auto s : segs) {
        seg.update(s.l, s.r + 1, seg.query(s.l, s.r) + s.c);
    }

    lint ans = seg.query(n - 1, n);
    std::cout << (ans == INF ? -1 : ans) << std::endl;
    return 0;
}


Measured memory_bytes: 5888