AtCoder problem 037

C++ solution:
#include <iostream>

#include <vector>

#include <algorithm>

using namespace std;



class RangeMax {

public:

	int size_ = 1;

	vector<long long> dat;



	void init(int sz) {

		while (size_ <= sz) size_ *= 2;

		dat.resize(size_ * 2, -(1LL << 60));

	}

	void update(int pos, long long x) {

		pos += size_;

		dat[pos] = x;

		while (pos >= 2) {

			pos >>= 1;

			dat[pos] = max(dat[pos * 2], dat[pos * 2 + 1]);

		}

	}

	long long query_(int l, int r, int a, int b, int u) {

		if (l <= a && b <= r) return dat[u];

		if (r <= a || b <= l) return -(1LL << 60);

		long long v1 = query_(l, r, a, (a + b) >> 1, u * 2);

		long long v2 = query_(l, r, (a + b) >> 1, b, u * 2 + 1);

		return max(v1, v2);

	}

	long long query(int l, int r) {

		return query_(l, r, 0, size_, 1);

	}

};



long long W, N;

long long L[1 << 18], R[1 << 18], V[1 << 18];

long long dp[509][10009];

RangeMax Z[509];



int main() {

	// Step #1. 入力

	cin >> W >> N;

	for (int i = 1; i <= N; i++) cin >> L[i] >> R[i] >> V[i];



	// Step #2. 初期化

	for (int i = 0; i <= N; i++) {

		for (int j = 0; j <= W; j++) dp[i][j] = -(1LL << 60);

		Z[i].init(W + 2);

	}

	dp[0][0] = 0;

	Z[0].update(0, 0);



	// Step #3. 動的計画法

	for (int i = 1; i <= N; i++) {

		for (int j = 0; j <= W; j++) dp[i][j] = dp[i - 1][j];

		for (int j = 0; j <= W; j++) {

			int cl = max(0, j - (int)R[i]), cr = max(0, j - (int)L[i] + 1);

			if (cl == cr) continue;

			long long val = Z[i - 1].query(cl, cr);

			if (val != -(1LL << 60)) {

				dp[i][j] = max(dp[i][j], val + V[i]);

			}

		}

		for (int j = 0; j <= W; j++) Z[i].update(j, dp[i][j]);

	}



	// Step #4. 出力

	if (dp[N][W] == -(1LL << 60)) cout << "-1" << endl;

	else cout << dp[N][W] << endl;

	return 0;

}


Python solution: import sys
from collections import defaultdict, Counter, deque
from itertools import permutations, combinations, product, combinations_with_replacement, groupby, accumulate
import operator
from math import sqrt, gcd, factorial
# from math import isqrt, prod,comb  # python3.8用(notpypy)
#from bisect import bisect_left,bisect_right
#from functools import lru_cache,reduce
#from heapq import heappush,heappop,heapify,heappushpop,heapreplace
#import numpy as np
#import networkx as nx
#from networkx.utils import UnionFind
#from numba import njit, b1, i1, i4, i8, f8
#from scipy.sparse import csr_matrix
#from scipy.sparse.csgraph import shortest_path, floyd_warshall, dijkstra, bellman_ford, johnson, NegativeCycleError
# numba例 @njit(i1(i4[:], i8[:, :]),cache=True) 引数i4配列、i8 2次元配列,戻り値i1
def input(): return sys.stdin.readline().rstrip()
def divceil(n, k): return 1+(n-1)//k  # n/kの切り上げを返す
def yn(hantei, yes='Yes', no='No'): print(yes if hantei else no)


class SparceTable:
    def __init__(self, A, op=min, e=10**10):
        self.n = len(A)
        self.op = op
        self.e = e
        self.table = [None]*(len(A).bit_length())  # [i, i+2^k)のop
        self.table[0] = A
        pre_table = A
        k = 0
        for k in range(len(A).bit_length()-1):
            pre_table = self.table[k]
            self.table[k+1] = [op(pre_table[i], pre_table[i+(1 << k)])
                               for i in range(len(pre_table)-(1 << k))]
            k += 1

    # [l, r)のop
    def query(self, l, r):
        l = min(max(0, l),self.n)
        r = min(max(0, r),self.n)
        if l == r:
            return self.e

        k = (r-l).bit_length()-1
        return self.op(self.table[k][l], self.table[k][r-(1 << k)])


def main():
    mod = 10**9+7
    mod2 = 998244353
    w, n = map(int, input().split())
    c=[-10**15]*(w+1)
    c[0]=0
    dp = SparceTable(c, op=max, e=-10**15)
    for _ in range(n):
        l, r, v = map(int, input().split())
        newdp=[0]*(w+1)
        for i in range(w+1):
            newdp[i]=max(dp.query(i-r,i-l+1)+v,dp.query(i,i+1))
        dp=SparceTable(newdp,op=max,e=-10**15)
        #print(newdp)
    print(max(-1,dp.query(w,w+1)))


if __name__ == '__main__':
    main()