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

#define _overload3(_1, _2, _3, name, ...) name
#define _rep(i, n) repi(i, 0, n)
#define repi(i, a, b) for(int i = int(a), i##_len = (b); i < i##_len; ++i)
#define rep(...) _overload3(__VA_ARGS__, repi, _rep, )(__VA_ARGS__)
#define _repr(i, n) repri(i, n, 0)
/* loop in [n,m] step -1 */
#define repri(i, a, b) for(int i = int(a), i##_len = (b); i >= i##_len; --i)
/* loop in [n,0] step -1 or [n,m] step -1 */
#define repr(...) _overload3(__VA_ARGS__, repri, _repr, )(__VA_ARGS__)
#define all(x) (x).begin(), (x).end()
#define debug(x) cerr << #x << ": " << (x) << '\n'
#define endl '\n'
typedef vector<int> vint;
typedef pair<int, int> pint;
#define CPP_STR(x) CPP_STR_I(x)
#define CPP_CAT(x, y) CPP_CAT_I(x, y)
#define CPP_STR_I(args...) #args
#define CPP_CAT_I(x, y) x##y
#define ASSERT(expr...) assert((expr))

/* type annotation */
using i8 = int8_t;
using u8 = uint8_t;
using i16 = int16_t;
using u16 = uint16_t;
using i32 = int32_t;
using u32 = uint32_t;
using i64 = int64_t;
using u64 = uint64_t;

using f32 = float;
using f64 = double;

constexpr i64 INF = 1'010'000'000'000'000'017LL;

constexpr i64 MOD = 1'000'000'007LL;

constexpr f64 EPS = 1e-12;

constexpr f64 PI = 3.14159265358979323846;

/* macros */
#define FOR(i, start, end)                             \
    for(i64 i = (start), CPP_CAT(i, xxxx_end) = (end); \
        i < CPP_CAT(i, xxxx_end); ++i)
#define REP(i, n) FOR(i, 0, n)
#define ALL(f, c, ...)                                               \
    (([&](decltype((c)) cccc) {                                      \
        return (f)(std::begin(cccc), std::end(cccc), ##__VA_ARGS__); \
    })(c))
template <typename C>
i64 SIZE(const C &c) {
    return static_cast<i64>(c.size());
}
template <typename T, size_t N>
i64 SIZE(const T (&)[N]) {
    return static_cast<i64>(N);
}
#define UNIQUE(v) v.erase(unique(v.begin(), v.end()), v.end())

/* marathon match */
#ifdef LOCAL
const i64 CYCLES_PER_SEC = 2800000000;
#else
const i64 CYCLES_PER_SEC = 2800000000;  // AtCoder
#endif

struct Timer {
    i64 start;

    Timer() { reset(); }

    void reset() { start = getCycle(); }

    inline double get() {
        return (double)(getCycle() - start) / CYCLES_PER_SEC * 1000;
    }

   private:
    inline i64 getCycle() {
        u32 low, high;
        __asm__ volatile("rdtsc" : "=a"(low), "=d"(high));
        return ((i64)low) | ((i64)high << 32);
    }
} timer;

class XorShift {
   public:
    unsigned int x, y, z, w;
    double nL[65536];

    XorShift() { init(); }

    void init() {
        x = 314159265;
        y = 358979323;
        z = 846264338;
        w = 327950288;
        double n = 1 / (double)(2 * 65536);
        for(int i = 0; i < 65536; i++) {
            nL[i] = log(((double)i / 65536) + n);
        }
    }

    inline unsigned int next() {
        unsigned int t = x ^ x << 11;
        x = y;
        y = z;
        z = w;
        return w = w ^ w >> 19 ^ t ^ t >> 8;
    }

    inline double nextLog() { return nL[next() & 0xFFFF]; }

    inline int nextInt(int m) { return (int)(next() % m); }

    int nextInt(int min, int max) { return min + nextInt(max - min + 1); }

    inline double nextDouble() { return (double)next() / ((long long)1 << 32); }
} rnd;

struct IoSetup {
    IoSetup() {
        cin.tie(nullptr);
        ios::sync_with_stdio(false);
        cout << fixed << setprecision(20);
        cerr << fixed << setprecision(20);
    }
} iosetup;

/* lambda recursion */
template <typename F>
class
#if defined(__has_cpp_attribute) && __has_cpp_attribute(nodiscard)
    [[nodiscard]]
#elif defined(__GNUC__) && __GNUC_PREREQ(3, 4)
__attribute__((warn_unused_result))
#endif  // defined(__has_cpp_attribute) && __has_cpp_attribute(nodiscard)
    FixPoint :
    F { public : explicit constexpr FixPoint(F &&f) noexcept :
            F(std::forward<F>(f)) {}

        template <typename... Args> constexpr decltype(auto)
        operator()(Args &&... args) const {
            return F::operator()(*this, std::forward<Args>(args)...);
}
}
;  // class FixPoint

template <typename F>
static inline constexpr decltype(auto) makeFixPoint(F &&f) noexcept {
    return FixPoint<F>{std::forward<F>(f)};
}

/* keep a max,min */
template <typename T, typename U, typename Comp = less<>>
bool chmax(T &xmax, const U &x, Comp comp = {}) {
    if(comp(xmax, x)) {
        xmax = x;
        return true;
    }
    return false;
}

template <typename T, typename U, typename Comp = less<>>
bool chmin(T &xmin, const U &x, Comp comp = {}) {
    if(comp(x, xmin)) {
        xmin = x;
        return true;
    }
    return false;
}

/* input,output operator for pair, vector and map */

/* input,output operator for pair and vector */
template <typename T1, typename T2>
ostream &operator<<(ostream &os, const pair<T1, T2> &p) {
    os << p.first << " " << p.second;
    return os;
}

template <typename T1, typename T2>
istream &operator>>(istream &is, pair<T1, T2> &p) {
    is >> p.first >> p.second;
    return is;
}

template <typename T>
ostream &operator<<(ostream &os, const vector<T> &v) {
    for(int i = 0; i < (int)v.size(); i++) {
        os << v[i] << (i + 1 != v.size() ? " " : "");
    }
    return os;
}

template <typename T>
ostream &operator<<(ostream &os, const vector<vector<T>> &v) {
    for(int i = 0; i < (int)v.size(); i++) {
        os << v[i] << (i + 1 != v.size() ? "\n" : "");
    }
    return os;
}

template <typename T>
istream &operator>>(istream &is, vector<T> &v) {
    for(T &in : v) is >> in;
    return is;
}

template <typename T, typename U>
ostream &operator<<(ostream &os, const map<T, U> &mp) {
    os << "{";
    for(auto x = mp.begin(); x != mp.end(); ++x) {
        os << x->first << ":" << x->second << (x != prev(mp.end()) ? ", " : "");
    }
    os << "}";
    return os;
}

using std::to_string;

auto to_string(std::string s) -> std::string { return s; }

auto to_string(char c) -> std::string { return std::string{c}; }

auto to_string(const char *s) -> std::string {
    return to_string((std::string)s);
}

auto to_string(bool b) -> std::string { return (b ? "true" : "false"); }

template <typename T, typename U>
auto to_string(std::pair<T, U> p) -> std::string {
    return "(" + to_string(p.first) + ", " + to_string(p.second) + ")";
}

template <size_t N>
auto to_string(std::bitset<N> bs) -> std::string {
    std::string res{};
    for(size_t i = 0; i < N; i++)
        res.insert(res.begin(), bs.test(i) ? '1' : '0');
    return res;
}

template <typename T>
auto to_string(T v) -> std::string {
    bool flg = false;
    std::string res = "[";
    for(auto const &x : v) {
        if(flg)
            res += ", ";
        else
            flg = true;
        res += to_string(x);
    }
    res += "]";
    return res;
}

/* initialize vector. usage: auto v = make_v<int>(N,0); */
template <typename T>
vector<T> make_v(size_t a) {
    return vector<T>(a);
}

template <typename T, typename... Ts>
auto make_v(size_t a, Ts... ts) {
    return vector<decltype(make_v<T>(ts...))>(a, make_v<T>(ts...));
}

/* fill vector. usage: fill_v(v,0); */
template <typename T, typename V>
typename enable_if<is_class<T>::value == 0>::type fill_v(T &t, const V &v) {
    t = v;
}

template <typename T, typename V>
typename enable_if<is_class<T>::value != 0>::type fill_v(T &t, const V &v) {
    for(auto &e : t) fill_v(e, v);
}

/* sum */
template <typename T>
T sum(vector<T> &v) {
    T ret = 0;
    for(T x : v) {
        ret += x;
    }
    return ret;
}
template <typename T>
auto sum(const T &a) {
    return a;
}
template <typename T, typename... A>
auto sum(const T &first, const A &... rest) {
    return sum(first) + sum(rest...);
}

#include <cassert>
#include <vector>

template <class Info>
struct edge {
    int from, to;
    Info info;
    edge(int to, Info info) : to(to), info(info) {}
    // edge(int from, int to, Info info) : from(from), to(to), info(info) {}
};

struct normal_edge {
    normal_edge() {}
};

template <class Info>
class graph {
   protected:
    using edge_type = edge<Info>;
    ::std::size_t N;
    ::std::vector<::std::vector<edge_type>> edges;

   public:
    graph(::std::size_t N_) : N(N_), edges(N_) {}
    virtual void add_edge(int x, int y, Info info) = 0;
    const ::std::vector<edge_type> &delta(int v) const {
        assert(v < N);
        return edges[v];
    }
    const ::std::vector<edge_type> &operator[](int v) const {
        return this->delta(v);
    }
    ::std::size_t size() const { return N; }
};

template <class Info>
class undirected_graph : public graph<Info> {
   public:
    undirected_graph(::std::size_t N) : graph<Info>(N) {}
    void add_edge(int x, int y, Info info) {
        this->edges[x].push_back(edge<Info>(y, info));
        this->edges[y].push_back(edge<Info>(x, info));
    }
};

template <class Info>
class directed_graph : public graph<Info> {
   public:
    directed_graph(::std::size_t N) : graph<Info>(N) {}
    void add_edge(int x, int y, Info info) {
        this->edges[x].push_back(edge<Info>(y, info));
    }
};

template <class Info>
class bipartite_graph : public undirected_graph<Info> {
    ::std::size_t A;
    ::std::size_t B;

   public:
    bipartite_graph(::std::size_t A_, ::std::size_t B_)
        : A(A_), B(B_), undirected_graph<Info>(A_ + B_) {}
    void add_edge(int x, int y, Info info) {
        undirected_graph<Info>::add_edge(x, y + A, info);
    }
};

/* dijkstra (depends on Graph_template) */
template <typename T>
class RadixHeap64 {
   public:
    using key_type = std::uint_fast64_t;
    using value_type = std::pair<key_type, T>;
    using reference = value_type &;
    using const_reference = const value_type &;
    using size_type = std::uint_fast32_t;

   private:
    static size_type bsr(const key_type x) {
        if(!x) return 0;
#ifdef __GNUC__
        return 64 - __builtin_clzll(x);
#else
        size_type t = 32;
        for(size_type i = 4; ~i; --i) {
            if(x & ~(((key_type)1 << t) - 1))
                t += (size_type)1 << i;
            else
                t -= (size_type)1 << i;
        }
        if(x & ~(((key_type)1 << t) - 1)) ++t;
        return t;
#endif
    }
    std::vector<value_type> v[65];
    key_type last;
    size_type size_;

   public:
    RadixHeap64() : last(0), size_(0) {}
    value_type pop() {
        assert(size_);
        --size_;
        if(v[0].empty()) {
            size_type i = 1;
            while(v[i].empty()) ++i;
            last = std::numeric_limits<key_type>::max();
            for(const auto &d : v[i]) last = std::min(last, d.first);
            for(const auto &d : v[i]) v[bsr(last ^ d.first)].push_back(d);
            v[i].clear();
        }
        value_type ret = v[0].back();
        v[0].pop_back();
        return ret;
    }
    void push(const_reference x) {
        assert(last <= x.first);
        ++size_;
        v[bsr(x.first ^ last)].push_back(x);
    }
    bool empty() const { return !size_; }
    size_type size() const { return size_; }
};

template <typename T>
vector<T> dijkstra(graph<T> &g, int s) {
    const auto INF = numeric_limits<T>::max();
    vector<T> dist(g.size(), INF);
    vector<int> b(g.size(), -1);

    RadixHeap64<T> que;
    dist[s] = 0;
    que.push(pair<i64, T>(dist[s], s));
    while(!que.empty()) {
        T cost;
        int idx;
        tie(cost, idx) = que.pop();
        if(dist[idx] < cost) continue;
        for(auto &e : g[idx]) {
            auto next_cost = cost + e.info;
            if(dist[e.to] <= next_cost) continue;
            dist[e.to] = next_cost;
            b[e.to] = idx;
            que.push(pair<i64, T>(dist[e.to], e.to));
        }
    }
    return dist;
}

int main() {
    int N, M;
    cin >> N >> M;
    directed_graph<i64> G(N);
    for(int i = 0; i < N - 1; ++i) {
        G.add_edge(i + 1, i, 0);
    }
    REP(i, M) {
        int L, R, C;
        cin >> L >> R >> C;
        L--, R--;
        G.add_edge(L, R, C);
    }
    auto dist = dijkstra(G, 0);
    cout << (dist[N - 1] == numeric_limits<i64>::max() ? -1 : dist[N - 1])
         << endl;
    return 0;
}

Measured memory_bytes: 12144