Problem:
Problem I:
Live Programming
A famous Japanese idol group, JAG48, is planning the program for its next live performance.
They have $N$ different songs, $song_1$, $song_2$, ..., and $song_N$. Each song has three integer param-
eters, $t_i$, $p_i$, and $f_i$: $t_i$ denotes the length of $song_i$, $p_i$ denotes the basic satisfaction points the
audience will get when $song_i$ is performed, and $f_i$ denotes the feature value of songi that affects
the audience's satisfaction. During the live performance, JAG48 can perform any number (but
at least one) of the $N$ songs, unless the total length of the chosen songs exceeds the length of
the live performance $T$. They can decide the order of the songs to perform, but they cannot
perform the same song twice or more.
The goal of this live performance is to maximize the total satisfaction points that the audience
will get. In addition to the basic satisfaction points of each song, the difference between the
feature values of the two songs that are performed consecutively affects the total satisfaction
points. If there is no difference, the audience will feel comfortable. However, the larger the
difference will be, the more frustrated the audience will be.
Thus, the total satisfaction points will be calculated as follows:
If $song_x$ is the first song of the live performance, the total satisfaction points just after
$song_x$ is equal to $p_x$.
If $song_x$ is the second or subsequent song of the live performance and is performed just
after $song_y$, $p_x -(f_x -f_y)^2$ is added to the total satisfaction points, because the audience
will get frustrated if $f_x$ and $f_y$ are different.
Help JAG48 find a program with the maximum total satisfaction points.
Input
The input is formatted as follows.
$N$ $T$
$t_1$ $p_1$ $f_1$
: : :
$t_N$ $p_N$ $f_N$
The first line contains two integers $N$ and $T$: the number of the available $song_s$ $N$ ($1 \leq N \leq
4,000$), and the length of the live performance $T$ ($1 \leq T \leq 4,000$).
The following $N$ lines represent the parameters of the songs. The $i$-th line of them contains three
integers, which are the parameters of $song_i$: the length $t_i$ ($1 \leq t_i \leq 4,000$), the basic satisfaction
points $p_i$ ($1 \leq p_i \leq 10^8$), and the feature value $f_i$ ($1 \leq f_i \leq 10^4$).
You can assume that there is at least one song whose length is less than or equal to $T$.
Output
Output the maximum total satisfaction points that the audience can get during the live performance.
Sample Input
2 10
10 200 1
10 100 100
Output for the Sample Input
200
Sample Input
3 15
5 100 1
5 100 2
5 100 4
Output for the Sample Input
295
Sample Input
3 10
5 200 200
5 200 201
5 300 1
Output for the Sample Input
399
Sample Input
3 20
5 100 200
5 100 201
5 300 1
Output for the Sample Input
300
Sample Input
5 61
14 49 7
31 46 4
30 55 5
52 99 1
34 70 3
Output for the Sample Input
103

Submitted solutions:

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define overload2(a, b, c, ...) c
#define overload3(a, b, c, d, ...) d
#define overload4(a, b, c, d, e ...) e
#define overload5(a, b, c, d, e, f ...) f
#define overload6(a, b, c, d, e, f, g ...) g
#define fast_io ios::sync_with_stdio(false); cin.tie(nullptr);
#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
typedef long long ll;
typedef long double ld;
#define chmin(a,b) a = min(a,b);
#define chmax(a,b) a = max(a,b);
#define bit_count(x) __builtin_popcountll(x)
#define leading_zero_count(x) __builtin_clz(x)
#define trailing_zero_count(x) __builtin_ctz(x)
#define gcd(a,b) __gcd(a,b)
#define lcm(a,b) a / gcd(a,b) * b
#define rep(...) overload3(__VA_ARGS__, rrep, rep1)(__VA_ARGS__)
#define rep1(i,n) for(int i = 0 ; i < n ; i++)
#define rrep(i,a,b) for(int i = a ; i < b ; i++)
#define repi(it,S) for(auto it = S.begin() ; it != S.end() ; it++)
#define pt(a) cout << a << endl;
#define print(...) printall(__VA_ARGS__);
#define debug(a) cout << #a << " " << a << endl;
#define all(a) a.begin(), a.end()
#define endl "\n";
#define v1(T,n,a) vector<T>(n,a)
#define v2(T,n,m,a) vector<vector<T>>(n,v1(T,m,a))
#define v3(T,n,m,k,a) vector<vector<vector<T>>>(n,v2(T,m,k,a))
#define v4(T,n,m,k,l,a) vector<vector<vector<vector<T>>>>(n,v3(T,m,k,l,a))
template<typename T,typename U>istream &operator>>(istream&is,pair<T,U>&p){is>>p.first>>p.second;return is;}
template<typename T,typename U>ostream &operator<<(ostream&os,const pair<T,U>&p){os<<p.first<<" "<<p.second;return os;}
template<typename T>istream &operator>>(istream&is,vector<T>&v){for(T &in:v){is>>in;}return is;}
template<typename T>ostream &operator<<(ostream&os,const vector<T>&v){for(auto it=v.begin();it!=v.end();){os<<*it<<((++it)!=v.end()?" ":"");}return os;}
template<typename T>istream &operator>>(istream&is,vector<vector<T>>&v){for(T &in:v){is>>in;}return is;}
template<typename T>ostream &operator<<(ostream&os,const vector<vector<T>>&v){for(auto it=v.begin();it!=v.end();){os<<*it<<((++it)!=v.end()?"\n":"");}return os;}
template<typename T>ostream &operator<<(ostream&os,const set<T>&v){for(auto it=v.begin();it!=v.end();){os<<*it<<((++it)!=v.end()?" ":"");}return os;}
template<typename T>ostream &operator<<(ostream&os,const multiset<T>&v){for(auto it=v.begin();it!=v.end();){os<<*it<<((++it)!=v.end()?" ":"");}return os;}
template<class... Args> void printall(Args... args){for(auto i:initializer_list<common_type_t<Args...>>{args...}) cout<<i<<" ";cout<<endl;}

const long long linf = 1000000000000000000LL;

template <typename T, T x_low, T x_high, T id>
struct DynamicLiChaoTree {
    struct Line {
        T a, b;
        Line(T a, T b): a(a), b(b) {}
        inline T get(T x) const { return a * x + b; }
    };

    struct Node {
        Line x;
        Node *l, *r;
        Node(const Line &x): x(x), l{nullptr}, r{nullptr} {}
    };

    Node *root;

    
    private:
        Node *_add_line(Node *t, Line &x, const T &l, const T &r, const T &x_l, const T &x_r) {
            if(!t) return new Node(x);

            T t_l = t->x.get(l);
            T t_r = t->x.get(r);

            if(t_l <= x_l && t_r <= x_r) return t;
            if(t_l >= x_l && t_r >=x_r) {
                t->x = x;
                return t;
            }
            T m = (l + r) / 2;
            if(m == r) --m;
            T t_m = t->x.get(m);
            T x_m = x.get(m);
            if(t_m > x_m) swap(t->x, x);
            if(x_l >= t_l) t->l = _add_line(t->l, x, l, m, t_l, t_m);
            else t->r = _add_line(t->r, x, m+1, r, t_m+x.a, t_r);
            return t;
        }

        Node *_add_segment(Node *t, Line &x, const T &a, const T &b, const T &l, const T &r, const T &x_l, const T &x_r) {
            if(r < a || b < l) return t;
            if(a <= l && r <= b) {
                Line y{x};
                return *add_line(t, y, l, r, x_l, x_r);
            }
            if(t) {
                T t_l = t->x.get(l);
                T t_r = t->x.get(r);
                if(t_l <= x_l && t_r <= x_r) return t;
            }
            else t = new Node(Line(0, id));
            T m = (l + r) / 2;
            if(m == r) --m;
            T x_m = x.get(m);
            t->l = _add_segment(t->l, x, a, b, l, m, x_l, x_m);
            t->r = _add_segment(t->r, x, a, b, m+1, r, x_m+x.a, x_r);
            return t;
        }

        T _query(Node *t, const T &l, const T &r, const T &x) const {
            if(!t) return id;
            if(l == r) return t->x.get(x);
            T m = (l + r) / 2;
            if(m == r) --m;
            if(x <= m) return min(t->x.get(x), _query(t->l, l, m, x));
            else return min(t->x.get(x), _query(t->r, m+1, r, x));
        }

    public:
        DynamicLiChaoTree(): root{nullptr} {}
        void add_line(const T &a, const T &b){
            Line x(a, b);
            root = _add_line(root, x, x_low, x_high, x.get(x_low), x.get(x_high));
        }
        void add_segment(const T &l, const T &r, const T &a, const T &b){
            Line x(a,b);
            root = _add_segment(root, x, l, r-1, x_low, x_high, x.get(x_low), x.get(x_high));
        }
        T query(const T &x) const {
            return _query(root, x_low, x_high, x);
        }
};

int main(){
    int n, T;
    cin >> n >> T;
    vector<tuple<ll,ll,ll>> A(n);
    rep(i,n){
        ll t, p, f;
        cin >> t >> p >> f;
        A[i] = {f,t,p};
    }
    sort(all(A));
    vector<vector<ll>> dp(n+1,vector<ll>(T+1,-1e18));
    vector<DynamicLiChaoTree<ll, 0, 1000000000LL, linf>> chtv;
    rep(i,T+1){
        DynamicLiChaoTree<ll, 0, 1000000000LL, linf> cht;
        chtv.push_back(cht);
    }
    rrep(i,1,n+1){
        auto [f,t,p] = A[i-1];
        rep(j,T+1){
            if(j+t>T) break;
            if(j == 0){
                dp[i][j+t] = p;
            }
            else{
                chmax(dp[i][j+t], p - f*f - chtv[j].query(f));
            }
        }
        rep(j,T+1){
            if(j+t>T) break;
            chtv[j+t].add_line(-2*f, -dp[i][j+t]+f*f);
        }
    }
    ll res = 0;
    rrep(i,1,n+1) rep(j,T+1) chmax(res,dp[i][j]);
    cout << res << endl;
}
accuracy: 1
time_ms: 280
memory_kb: 118088
final_rank: 16

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

constexpr long long inf = 1001001001001001001;

//https://ei1333.github.io/library/structure/convex-hull-trick/dynamic-li-chao-tree.hpp
template< typename T, T x_low, T x_high, T id >
struct DynamicLiChaoTree {
    
    struct Line {
        T a, b;
        
        Line(T a, T b) : a(a), b(b) {}
        
        inline T get(T x) const { return a * x + b; }
    };
    
    struct Node {
        Line x;
        Node *l, *r;
        
        Node(const Line &x) : x{x}, l{nullptr}, r{nullptr} {}
    };
    
    Node *root;
    
    DynamicLiChaoTree() : root{nullptr} {}
    
    Node *add_line(Node *t, Line &x, const T &l, const T &r, const T &x_l, const T &x_r) {
        if(!t) return new Node(x);
        
        T t_l = t->x.get(l), t_r = t->x.get(r);
        
        if(t_l <= x_l && t_r <= x_r) {
            return t;
        } else if(t_l >= x_l && t_r >= x_r) {
            t->x = x;
            return t;
        } else {
            T m = (l + r) / 2;
            if(m == r) --m;
            T t_m = t->x.get(m), x_m = x.get(m);
            if(t_m > x_m) {
                swap(t->x, x);
                if(x_l >= t_l) t->l = add_line(t->l, x, l, m, t_l, t_m);
                else t->r = add_line(t->r, x, m + 1, r, t_m + x.a, t_r);
            } else {
                if(t_l >= x_l) t->l = add_line(t->l, x, l, m, x_l, x_m);
                else t->r = add_line(t->r, x, m + 1, r, x_m + x.a, x_r);
            }
            return t;
        }
    }
    
    void add_line(const T &a, const T &b) {
        Line x(a, b);
        root = add_line(root, x, x_low, x_high, x.get(x_low), x.get(x_high));
    }
    
    Node *add_segment(Node *t, Line &x, const T &a, const T &b, const T &l, const T &r, const T &x_l, const T &x_r) {
        if(r < a || b < l) return t;
        if(a <= l && r <= b) {
            Line y{x};
            return add_line(t, y, l, r, x_l, x_r);
        }
        if(t) {
            T t_l = t->x.get(l), t_r = t->x.get(r);
            if(t_l <= x_l && t_r <= x_r) return t;
        } else {
            t = new Node(Line(0, id));
        }
        T m = (l + r) / 2;
        if(m == r) --m;
        T x_m = x.get(m);
        t->l = add_segment(t->l, x, a, b, l, m, x_l, x_m);
        t->r = add_segment(t->r, x, a, b, m + 1, r, x_m + x.a, x_r);
        return t;
    }
    
    void add_segment(const T &l, const T &r, const T &a, const T &b) {
        Line x(a, b);
        root = add_segment(root, x, l, r - 1, x_low, x_high, x.get(x_low), x.get(x_high));
    }
    
    T query(const Node *t, const T &l, const T &r, const T &x) const {
        if(!t) return id;
        if(l == r) return t->x.get(x);
        T m = (l + r) / 2;
        if(m == r) --m;
        if(x <= m) return min(t->x.get(x), query(t->l, l, m, x));
        else return min(t->x.get(x), query(t->r, m + 1, r, x));
    }
    
    T query(const T &x) const {
        return query(root, x_low, x_high, x);
    }
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int N,T;
    cin >> N >> T;
    vector<array<long long,3>>tmp(N);
    for(int i = 0; i < N; i++) {
        cin >> tmp[i][1] >> tmp[i][2] >> tmp[i][0];
    }
    sort(tmp.begin(),tmp.end());
    vector<DynamicLiChaoTree<long long,0,2001001,inf>>tree(T+1);
    long long ans = 0;
    for(int i = 0; i < N; i++) {
        for(int j = T; j >= 0; j--) {
            if(j+tmp[i][1] <= T) {
                if(j == 0) {
                    ans = max(ans,tmp[i][2]);
                    tree[tmp[i][1]].add_line(-tmp[i][0],-(tmp[i][2]-tmp[i][0]*tmp[i][0]));
                }
                else {
                    long long q = -tree[j].query(2*tmp[i][0])-tmp[i][0]*tmp[i][0]+tmp[i][2];
                    ans = max(ans,q);
                    tree[j+tmp[i][1]].add_line(-tmp[i][0],-(q-tmp[i][0]*tmp[i][0]));
                }
            }
        }
    }
    cout << ans << endl;
}
accuracy: 1
time_ms: 100
memory_kb: 5824
final_rank: 3

code_snippet: #pragma GCC optimize("Ofast")
#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
#include <queue>
#include <cstdio>
#include <ctime>
#include <assert.h>
#include <chrono>
#include <random>
#include <numeric>
#include <set>
#include <deque>
#include <stack>
#include <sstream>
#include <utility>
#include <cstring>
#include <unordered_map>
#include <unordered_set>
#include <tuple>
#include <array>
#include <bitset>
using namespace std;
typedef long long int ll;
typedef unsigned long long ull;

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
ll myRand(ll B) {
    return (ull)rng() % B;
}
inline double time() {
    return static_cast<long double>(chrono::duration_cast<chrono::nanoseconds>(chrono::steady_clock::now().time_since_epoch()).count()) * 1e-9;
}

// 最悪計算量普通に3乗だと思うけど、落とすの大変かも、みたいなインチキDP
int main(){
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    int n,T; cin >> n >> T;
    vector<vector<pair<ll,int>>> dp(T+1);
    vector<pair<int,pair<int,int>>> v(n);
    for(int i=0;i<n;i++){
        int t,p,f; cin >> t >> p >> f;
        v[i] = {f,{t,p}};
    }
    sort(v.begin(), v.end());
    for(int i=0;i<n;i++){
        int f = v[i].first;
        int t = v[i].second.first;
        int p = v[i].second.second;
        auto psh = [&](int tt,int ff,ll val)->void{
            while(dp[tt].size() and dp[tt].back().first <= val){
                dp[tt].pop_back();
            }
            dp[tt].push_back({val,ff});
        };
        for(int j=T-t;j>0;j--){
            if(!dp[j].size()) continue;
            ll val = 0;
            for(auto pre:dp[j]){
                ll vv = pre.first+p-(ll)(pre.second-f)*(pre.second-f);
                val = max(val, vv);
            }
            psh(j+t, f, val);
        }
        if(t <= T){ // 0からの遷移
            ll val = p;
            psh(t, f, val);
        }
    }
    ll res = 0;
    for(int i=0;i<=T;i++){
        if(dp[i].size()) res = max(res, dp[i][0].first);
    }
    cout << res << endl;
}
accuracy: 1
time_ms: 70
memory_kb: 4384
final_rank: 2

code_snippet: #pragma GCC optimize("Ofast")
#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
#include <queue>
#include <cstdio>
#include <ctime>
#include <assert.h>
#include <chrono>
#include <random>
#include <numeric>
#include <set>
#include <deque>
#include <stack>
#include <sstream>
#include <utility>
#include <cstring>
#include <unordered_map>
#include <unordered_set>
#include <tuple>
#include <array>
#include <bitset>
using namespace std;
typedef long long int ll;
typedef unsigned long long ull;

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
ll myRand(ll B) {
    return (ull)rng() % B;
}
inline double time() {
    return static_cast<long double>(chrono::duration_cast<chrono::nanoseconds>(chrono::steady_clock::now().time_since_epoch()).count()) * 1e-9;
}

int main(){
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    int n,T; cin >> n >> T;
    vector<vector<pair<ll,int>>> dp(T+1);
    vector<pair<int,pair<int,int>>> v(n);
    for(int i=0;i<n;i++){
        int t,p,f; cin >> t >> p >> f;
        v[i] = {f,{t,p}};
    }
    sort(v.begin(), v.end());
    for(int i=0;i<n;i++){
        int f = v[i].first;
        int t = v[i].second.first;
        int p = v[i].second.second;
        auto psh = [&](int tt,int ff,ll val)->void{
            while(dp[tt].size() and dp[tt].back().first <= val){
                dp[tt].pop_back();
            }
            dp[tt].push_back({val,ff});
        };
        for(int j=T-t;j>0;j--){
            if(!dp[j].size()) continue;
            ll val = 0;
            for(auto pre:dp[j]){
                ll vv = pre.first+p-(ll)(pre.second-f)*(pre.second-f);
                val = max(val, vv);
            }
            psh(j+t, f, val);
        }
        if(t <= T){ // 0からの遷移
            ll val = p;
            psh(t, f, val);
        }
    }
    ll res = 0;
    for(int i=0;i<=T;i++){
        if(dp[i].size()) res = max(res, dp[i][0].first);
    }
    cout << res << endl;
}
accuracy: 1
time_ms: 60
memory_kb: 4560
final_rank: 1

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=998244353,MAX=4005;
const ll INF=1LL<<61;

/**
 * Author: Simon Lindholm
 * Date: 2017-04-20
 * License: CC0
 * Source: own work
 * Description: Container where you can add lines of the form kx+m, and query maximum values at points x.
 *  Useful for dynamic programming (``convex hull trick'').
 * Time: O(\log N)
 * Status: stress-tested
 */
//pragma once

struct Line {
    mutable ll k, m, p;
    bool operator<(const Line& o) const { return k < o.k; }
    bool operator<(ll x) const { return p < x; }
};

struct LineContainer : multiset<Line, less<>> {
    // (for doubles, use inf = 1/.0, div(a,b) = a/b)
    static const ll inf = LLONG_MAX;
    ll div(ll a, ll b) { // floored division
        return a / b - ((a ^ b) < 0 && a % b); }
    bool isect(iterator x, iterator y) {
        if (y == end()) return x->p = inf, 0;
        if (x->k == y->k) x->p = x->m > y->m ? inf : -inf;
        else x->p = div(y->m - x->m, x->k - y->k);
        return x->p >= y->p;
    }
    void add(ll k, ll m) {
        auto z = insert({k, m, 0}), y = z++, x = y;
        while (isect(y, z)) z = erase(z);
        if (x != begin() && isect(--x, y)) isect(x, y = erase(y));
        while ((y = x) != begin() && (--x)->p >= y->p)
            isect(x, erase(y));
    }
    ll query(ll x) {
        if(empty()) return -INF;
        auto l = *lower_bound(x);
        return l.k * x + l.m;
    }
};

ll dp[MAX][MAX];

int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    int N,T;cin>>N>>T;
    vector<tuple<ll,ll,ll>> S(N);
    for(int i=0;i<N;i++){
        int a,b,c;cin>>a>>b>>c;
        S[i]={a,b,c};
    }
    sort(all(S),[](auto a,auto b){
        return (get<2>(a))<(get<2>(b));
    });
    
    for(int i=0;i<=T;i++) for(int j=0;j<=N;j++) dp[i][j]=-INF;
    
    vector<LineContainer> LC(T+1);
    
    for(int j=0;j<N;j++){
        auto [t,p,f]=S[j];
        for(int i=T;i>=t;i--){
            if(i==t){
                dp[i][j]=p;
                LC[i].add(2*f,-f*f+dp[i][j]);
            }else{
                ll x=LC[i-t].query(f);
                if(x==-INF) continue;
                dp[i][j]=x-f*f+p;
                LC[i].add(2*f,-f*f+dp[i][j]);
            }
        }
    }
    
    ll ans=-INF;
    
    for(int i=0;i<=T;i++) for(int j=0;j<N;j++) chmax(ans,dp[i][j]);
    
    cout<<ans<<endl;
}
accuracy: 1
time_ms: 1230
memory_kb: 132224
final_rank: 18

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for (int i = 0; i < n; i++)
#define rep2(i, x, n) for (int i = x; i <= n; i++)
#define rep3(i, x, n) for (int i = x; i >= n; i--)
#define each(e, v) for (auto &e : v)
#define pb push_back
#define eb emplace_back
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
#define sz(x) (int)x.size()
using ll = long long;
using pii = pair<int, int>;
using pil = pair<int, ll>;
using pli = pair<ll, int>;
using pll = pair<ll, ll>;

template <typename T>
bool chmax(T &x, const T &y) {
    return (x < y) ? (x = y, true) : false;
}

template <typename T>
bool chmin(T &x, const T &y) {
    return (x > y) ? (x = y, true) : false;
}

template <typename T>
int flg(T x, int i) {
    return (x >> i) & 1;
}

template <typename T>
void print(const vector<T> &v, T x = 0) {
    int n = v.size();
    for (int i = 0; i < n; i++) cout << v[i] + x << (i == n - 1 ? '\n' : ' ');
    if (v.empty()) cout << '\n';
}

template <typename T>
void printn(const vector<T> &v, T x = 0) {
    int n = v.size();
    for (int i = 0; i < n; i++) cout << v[i] + x << '\n';
}

template <typename T>
int lb(const vector<T> &v, T x) {
    return lower_bound(begin(v), end(v), x) - begin(v);
}

template <typename T>
int ub(const vector<T> &v, T x) {
    return upper_bound(begin(v), end(v), x) - begin(v);
}

template <typename T>
void rearrange(vector<T> &v) {
    sort(begin(v), end(v));
    v.erase(unique(begin(v), end(v)), end(v));
}

template <typename T>
vector<int> id_sort(const vector<T> &v, bool greater = false) {
    int n = v.size();
    vector<int> ret(n);
    iota(begin(ret), end(ret), 0);
    sort(begin(ret), end(ret), [&](int i, int j) { return greater ? v[i] > v[j] : v[i] < v[j]; });
    return ret;
}

template <typename S, typename T>
pair<S, T> operator+(const pair<S, T> &p, const pair<S, T> &q) {
    return make_pair(p.first + q.first, p.second + q.second);
}

template <typename S, typename T>
pair<S, T> operator-(const pair<S, T> &p, const pair<S, T> &q) {
    return make_pair(p.first - q.first, p.second - q.second);
}

template <typename S, typename T>
istream &operator>>(istream &is, pair<S, T> &p) {
    S a;
    T b;
    is >> a >> b;
    p = make_pair(a, b);
    return is;
}

template <typename S, typename T>
ostream &operator<<(ostream &os, const pair<S, T> &p) {
    return os << p.first << ' ' << p.second;
}

struct io_setup {
    io_setup() {
        ios_base::sync_with_stdio(false);
        cin.tie(NULL);
        cout << fixed << setprecision(15);
    }
} io_setup;

const int inf = (1 << 30) - 1;
const ll INF = (1LL << 60) - 1;
const int MOD = 1000000007;
// const int MOD = 998244353;

template <typename T, bool is_min = true>
struct Convex_Hull_Trick {
    struct Line {
        T a, b;

        Line(const T &a, const T &b) : a(a), b(b) {}

        T get(const T &x) { return a * x + b; }
    };

    deque<Line> ls;

    Convex_Hull_Trick(){};

    bool empty() const { return ls.empty(); }

    bool judge(const Line &l1, const Line &l2, const Line &l3) const { // (l1,l2,l3) の中で l2 を消してもいいか
        T a1 = l2.a - l1.a, b1 = l2.b - l1.b;
        T a2 = l3.a - l2.a, b2 = l3.b - l2.b;
        // return a2 * b1 <= a1 * b2;
        return __int128_t(a2) * b1 <= __int128_t(a1) * b2;
    }

    void add_line_left(const Line &l) { // 最小値クエリなら傾き単調増加、最大値クエリなら傾き単調減少
        assert(empty() || l.a >= ls.front().a);
        if (!empty() && l.a == ls.front().a) {
            if (l.b >= ls.front().b) return;
            ls.pop_front();
        }
        while (ls.size() >= 2) {
            Line l2 = ls.front(), l3 = ls[1];
            if (!judge(l, l2, l3)) break;
            ls.pop_front();
        }
        ls.push_front(l);
    }

    void add_line_left(const T &a, const T &b) { add_line_left(Line(is_min ? a : -a, is_min ? b : -b)); }

    void add_line_right(const Line &l) { // 最小値クエリなら傾き単調減少、最大値クエリなら傾き単調増加
        assert(empty() || ls.back().a >= l.a);
        if (!empty() && ls.back().a == l.a) {
            if (ls.back().b <= l.b) return;
            ls.pop_back();
        }
        while (ls.size() >= 2) {
            Line l1 = ls[ls.size() - 2], l2 = ls.back();
            if (!judge(l1, l2, l)) break;
            ls.pop_back();
        }
        ls.push_back(l);
    }

    void add_line_right(const T &a, const T &b) { add_line_right(Line(is_min ? a : -a, is_min ? b : -b)); }

    T query(const T &x) {
        assert(!empty());
        int l = 0, r = ls.size();
        while (r - l > 1) {
            int m = (l + r) / 2;
            (ls[m - 1].get(x) >= ls[m].get(x) ? l : r) = m;
        }
        T ret = ls[l].get(x);
        return is_min ? ret : -ret;
    }

    T query_monotone_inc(const T &x) {
        assert(!empty());
        while (ls.size() >= 2 && ls.front().get(x) >= ls[1].get(x)) ls.pop_front();
        T ret = ls.front().get(x);
        return is_min ? ret : -ret;
    }

    T query_monotone_dec(const T &x) {
        assert(!empty());
        while (ls.size() >= 2 && ls[ls.size() - 2].get(x) <= ls.back().get(x)) ls.pop_back();
        T ret = ls.back().get(x);
        return is_min ? ret : -ret;
    }
};

int main() {
    int N, T;
    cin >> N >> T;

    vector<ll> t(N), p(N), f(N);
    rep(i, N) cin >> t[i] >> p[i] >> f[i];

    vector<int> v = id_sort(f);

    vector<vector<ll>> dp(N + 1, vector<ll>(T + 1, -INF));
    dp[0][0] = 0;

    vector<Convex_Hull_Trick<ll, false>> cht(T + 1);

    rep(i, N) {
        int e = v[i];
        rep3(j, T - t[e], 0) {
            if (cht[j].empty()) continue;
            ll ma = cht[j].query_monotone_inc(f[e]);
            ma += p[e] - f[e] * f[e];
            chmax(dp[i + 1][j + t[e]], ma);
            cht[j + t[e]].add_line_right(2 * f[e], ma - f[e] * f[e]);
        }
        rep2(j, t[e], T) {
            cht[j].add_line_right(2 * f[e], p[e] - f[e] * f[e]);
            chmax(dp[i + 1][j], p[e]);
        }
    }

    ll ans = -INF;
    rep(i, N + 1) chmax(ans, *max_element(all(dp[i])));
    cout << ans << '\n';
}
accuracy: 1
time_ms: 280
memory_kb: 118884
final_rank: 17

code_snippet: #line 1 "test/aoj/other/2725-CHT.test.cpp"
#define PROBLEM "https://onlinejudge.u-aizu.ac.jp/problems/2725"
#line 2 "other/template.hpp"

#include<bits/stdc++.h>

#ifndef __COUNTER__
#define __COUNTER__ __LINE__
#endif

#define REP_SELECTER(a, b, c, d, e, ...) e
#define REP1_0(b, c) REP1_1(b, c)
#define REP1_1(b, c) for (ll REP_COUNTER_ ## c = 0; REP_COUNTER_ ## c < (ll)(b); ++ REP_COUNTER_ ## c)
#define REP1(b) REP1_0(b, __COUNTER__)
#define REP2(i, b) for (ll i = 0; i < (ll)(b); ++i)
#define REP3(i, a, b) for (ll i = (ll)(a); i < (ll)(b); ++i)
#define REP4(i, a, b, c) for (ll i = (ll)(a); i < (ll)(b); i += (ll)(c))
#define rep(...) REP_SELECTER(__VA_ARGS__, REP4, REP3, REP2, REP1) (__VA_ARGS__)
#define RREP2(i, a) for (ll i = (ll)(a) - 1; i >= 0; --i)
#define RREP3(i, a, b) for (ll i = (ll)(a) - 1; i >= (ll)(b); --i)
#define RREP4(i, a, b, c) for (ll i = (ll)(a) - 1; i >= (ll)(b); i -= (ll)(c))
#define rrep(...) REP_SELECTER(__VA_ARGS__, RREP4, RREP3, RREP2) (__VA_ARGS__)
#define REPS2(i, b) for (ll i = 1; i <= (ll)(b); ++i)
#define REPS3(i, a, b) for (ll i = (ll)(a) + 1; i <= (ll)(b); ++i)
#define REPS4(i, a, b, c) for (ll i = (ll)(a) + 1; i <= (ll)(b); i += (ll)(c))
#define reps(...) REP_SELECTER(__VA_ARGS__, REPS4, REPS3, REPS2) (__VA_ARGS__)
#define RREPS2(i, a) for (ll i = (ll)(a); i > 0; --i)
#define RREPS3(i, a, b) for (ll i = (ll)(a); i > (ll)(b); --i)
#define RREPS4(i, a, b, c) for (ll i = (ll)(a); i > (ll)(b); i -= (ll)(c))
#define rreps(...) REP_SELECTER(__VA_ARGS__, RREPS4, RREPS3, RREPS2) (__VA_ARGS__)

#define all(v) (v).begin(), (v).end()

#if __cplusplus >= 201402L
#define CONSTEXPR constexpr
#else
#define CONSTEXPR
#endif

#ifdef __cpp_if_constexpr
#define IF_CONSTEXPR constexpr
#else
#define IF_CONSTEXPR
#endif

using ll = long long;
using ull = unsigned long long;
using ld = long double;
using PLL = std::pair<ll, ll>;
template<class T> using prique = std::priority_queue<T, std::vector<T>, std::greater<T>>;

template<class T> class infinity {
  public:
    static constexpr T value = std::numeric_limits<T>::max() / 2;
    static constexpr T mvalue = std::numeric_limits<T>::min() / 2;
    static constexpr T max = std::numeric_limits<T>::max();
    static constexpr T min = std::numeric_limits<T>::min();
};

#if __cplusplus <= 201402L
template<class T> constexpr T infinity<T>::value;
template<class T> constexpr T infinity<T>::mvalue;
template<class T> constexpr T infinity<T>::max;
template<class T> constexpr T infinity<T>::min;
#endif

#if __cplusplus >= 201402L
template<class T> constexpr T INF = infinity<T>::value;
#endif

constexpr ll inf = infinity<ll>::value;
constexpr ld EPS = 1e-8;
constexpr ld PI = 3.1415926535897932384626;

template<class T, class U> std::ostream& operator<<(std::ostream& ost, const std::pair<T, U>& p) {
    return ost << p.first << ' ' << p.second;
}
template<class T, class U> std::istream& operator>>(std::istream& ist, std::pair<T, U>& p) {
    return ist >> p.first >> p.second;
}

template<class Container,
        typename std::enable_if<!std::is_same<Container, std::string>::value>::type* = nullptr>
auto operator<<(std::ostream& ost, const Container& cont)
        -> decltype(cont.begin(), cont.end(), ost)
{
    for (auto itr = cont.begin(); itr != cont.end(); ++itr) {
        if (itr != cont.begin()) ost << ' ';
        ost << *itr;
    }
    return ost;
}
template<class Container,
        typename std::enable_if<!std::is_same<Container, std::string>::value>::type* = nullptr>
auto operator>>(std::istream& ist, Container& cont)
        -> decltype(cont.begin(), cont.end(), ist)
{
    for (auto itr = cont.begin(); itr != cont.end(); ++itr) ist >> *itr;
    return ist;
}

template<class T, class U> inline constexpr bool chmin(T &a, const U &b) noexcept {
    return a > b ? a = b, true : false;
}
template<class T, class U> inline constexpr bool chmax(T &a, const U &b) noexcept {
    return a < b ? a = b, true : false;
}

inline CONSTEXPR ll gcd(ll a, ll b) noexcept {
    while (b) {
        const ll c = a;
        a = b;
        b = c % b;
    }
    return a;
}
inline CONSTEXPR ll lcm(ll a, ll b) noexcept {
    return a / gcd(a, b) * b;
}

inline CONSTEXPR bool is_prime(ll N) noexcept {
    if (N <= 1) return false;
    for (ll i = 2; i * i <= N; ++i) {
        if (N % i == 0) return false;
    }
    return true;
}
inline std::vector<ll> prime_factor(ll N) noexcept {
    std::vector<ll> res;
    for (ll i = 2; i * i <= N; ++i) {
        while (N % i == 0) {
            res.push_back(i);
            N /= i;
        }
    }
    if (N != 1) res.push_back(N);
    return res;
}

inline CONSTEXPR ll my_pow(ll a, ll b) noexcept {
    ll res = 1;
    while (b) {
        if (b & 1) res *= a;
        b >>= 1;
        a *= a;
    }
    return res;
}
inline CONSTEXPR ll mod_pow(ll a, ll b, ll mod) noexcept {
    a %= mod;
    ll res = 1;
    while (b) {
        if (b & 1) (res *= a) %= mod;
        b >>= 1;
        (a *= a) %= mod;
    }
    return res;
}

PLL extGCD(ll a, ll b) noexcept {
    if (b == 0) return PLL{1, 0};
    PLL p = extGCD(b, a % b);
    std::swap(p.first, p.second);
    p.second -= p.first * (a / b);
    if (p.first < 0) {
        p.first += b;
        p.second -= a;
    }
    return p;
}
ll mod_inv(ll a, ll mod) noexcept {
    const PLL p = extGCD(a, mod);
    assert(p.first * a + p.second * mod == 1);
    return p.first;
}
PLL ChineseRemainder(ll b1, ll m1, ll b2, ll m2) noexcept {
    const PLL p = extGCD(m1, m2);
    const ll g = p.first * m1 + p.second * m2;
    const ll l = m1 / g * m2;
    if ((b2 - b1) % g != 0) return PLL{-1, -1};
    const ll x = (b2 - b1) / g * p.first % (m2 / g);
    return {(x * m1 + b1 + l) % l, l};
}
PLL ChineseRemainders(const std::vector<ll>& b, const std::vector<ll>& m) noexcept {
    PLL res{0, 1};
    rep (i, b.size()) {
        res = ChineseRemainder(res.first, res.second, b[i], m[i]);
        if (res.first == -1) return res;
    }
    return res;
}

template<class F> class RecLambda {
  private:
    F f;
  public:
    explicit constexpr RecLambda(F&& f_) : f(std::forward<F>(f_)) {}
    template<class... Args> constexpr auto operator()(Args&&... args) const
            -> decltype(f(*this, std::forward<Args>(args)...)) {
        return f(*this, std::forward<Args>(args)...);
    }
};

template<class F> inline constexpr RecLambda<F> rec_lambda(F&& f) {
    return RecLambda<F>(std::forward<F>(f));
}

template<class Head, class... Tails> struct multi_dim_vector {
    using type = std::vector<typename multi_dim_vector<Tails...>::type>;
};
template<class T> struct multi_dim_vector<T> {
    using type = T;
};

template<class T, class Arg> constexpr std::vector<T> make_vec(int n, Arg&& arg) {
    return std::vector<T>(n, std::forward<Arg>(arg));
}
template<class T, class... Args>
constexpr typename multi_dim_vector<Args..., T>::type make_vec(int n, Args&&... args) {
    return typename multi_dim_vector<Args..., T>::type (n, make_vec<T>(std::forward<Args>(args)...));
}

inline CONSTEXPR int popcnt(ull x) {
#if __cplusplus >= 202002L
    return std::popcount(x);
#endif
    x = (x & 0x5555555555555555) + ((x >> 1 ) & 0x5555555555555555);
    x = (x & 0x3333333333333333) + ((x >> 2 ) & 0x3333333333333333);
    x = (x & 0x0f0f0f0f0f0f0f0f) + ((x >> 4 ) & 0x0f0f0f0f0f0f0f0f);
    x = (x & 0x00ff00ff00ff00ff) + ((x >> 8 ) & 0x00ff00ff00ff00ff);
    x = (x & 0x0000ffff0000ffff) + ((x >> 16) & 0x0000ffff0000ffff);
    return (x & 0x00000000ffffffff) + ((x >> 32) & 0x00000000ffffffff);
}

template<class T> class presser : public std::vector<T> {
  private:
    using Base = std::vector<T>;
  public:
    using Base::Base;
    presser(const std::vector<T>& vec) : Base(vec) {}
    void push(const std::vector<T>& vec) {
        int n = this->size();
        this->resize(n + vec.size());
        std::copy(all(vec), this->begin() + n);
    }
    int build() {
        std::sort(this->begin(), this->end());
        this->erase(std::unique(this->begin(), this->end()), this->end());
        return this->size();
    }
    int get_index(const T& val) const {
        return static_cast<int>(std::lower_bound(this->begin(), this->end(), val) - this->begin());
    }
    std::vector<int> pressed(const std::vector<T>& vec) const {
        std::vector<int> res(vec.size());
        rep (i, vec.size()) res[i] = this->get_index(vec[i]);
        return res;
    }
    void press(std::vector<T>& vec) const {
        static_assert(std::is_integral<T>::value, "cannot convert from int type");
        rep (i, vec.size()) vec[i] = this->get_index(vec[i]);
    }
};
#line 2 "data-struct/cht/ConvexHullTrickAddMonotone.hpp"

#line 4 "data-struct/cht/ConvexHullTrickAddMonotone.hpp"

template<class T = ll, bool is_max = false> class ConvexHullTrickAddMonotone {
  protected:
    struct Line {
        T a, b;
        bool is_query;
        mutable const Line* nxt;
        T get(T x) const { return a * x + b; }
        Line() = default;
        Line(T a, T b, bool i = false) : a(a), b(b), is_query(i), nxt(nullptr) {}
        friend bool operator<(const Line& lhs, const Line& rhs) {
            assert(!lhs.is_query || !rhs.is_query);
            if (lhs.is_query) {
                if (rhs.nxt == nullptr) return true;
                return rhs.get(lhs.a) < rhs.nxt->get(lhs.a);
            }
            if (rhs.is_query) {
                if (lhs.nxt == nullptr) return false;
                return lhs.get(rhs.a) > lhs.nxt->get(rhs.a);
            }
            return lhs.a == rhs.a ? lhs.b < rhs.b : lhs.a < rhs.a;
        }
    };
    std::deque<Line> que;
    bool is_necessary(const typename std::deque<Line>::iterator& itr) {
        if (itr == que.begin() || itr == prev(que.end())) return true;
        if (itr->a == prev(itr)->a) return itr->b < prev(itr)->b;
        if (itr->a == next(itr)->a) return itr->b < next(itr)->b;
        return (__int128_t)(itr->b - prev(itr)->b) * (next(itr)->a - itr->a)
            <  (__int128_t)(itr->b - next(itr)->b) * (prev(itr)->a - itr->a);
    }
  public:
    ConvexHullTrickAddMonotone() = default;
    void add_line(T a, T b) {
        if IF_CONSTEXPR (is_max) a = - a, b = - b;
        typename std::deque<Line>::iterator itr;
        if (que.empty() || que.back().a <= a) {
            que.push_back(Line{a, b});
            itr = prev(que.end());
        }
        else {
            assert(a <= que.front().a);
            que.push_front(Line{a, b});
            itr = que.begin();
        }
        if (!is_necessary(itr)) {
            que.erase(itr);
            return;
        }
        while (itr != que.begin() && !is_necessary(prev(itr))) {
            que.pop_back(); que.pop_back();
            que.push_back(Line{a, b});
            itr = prev(que.end());
        }
        while (itr != prev(que.end()) && !is_necessary(next(itr))) {
            que.pop_front(); que.pop_front();
            que.push_front(Line{a, b});
            itr = que.begin();
        }
        if (itr != que.begin()) prev(itr)->nxt = &*itr;
        if (itr != prev(que.end())) itr->nxt = &*next(itr);
        else itr->nxt = nullptr;
    }
    T get_min(T x) const {
        auto itr = lower_bound(que.begin(), que.end(), Line{x, 0, true});
        if IF_CONSTEXPR (is_max) return - itr->get(x);
        return itr->get(x);
    }
    T inc_get_min(T x) {
        while (que.size() > 1 && que.begin()->get(x) > next(que.begin())->get(x)) que.pop_front();
        if IF_CONSTEXPR (is_max) return - que.front().get(x);
        return que.front().get(x);
    }
    T dec_get_min(T x) {
        while (que.size() > 1 && prev(que.end())->get(x) > prev(que.end(), 2)->get(x)) que.pop_back();
        if IF_CONSTEXPR (is_max) return - que.back().get(x);
        return que.back().get(x);
    }
    bool empty() const {
        return que.empty();
    }
};

/**
 * @brief ConvexHullTrickAddMonotone
 * @docs docs/ConvexHullTrickAddMonotone.md
 */
#line 4 "test/aoj/other/2725-CHT.test.cpp"
using namespace std;
int main() {
    int N, T; cin >> N >> T;
    vector<array<ll, 3>> s(N); cin >> s;
    sort(s.begin(), s.end(), [](auto a, auto b) -> bool { return a[2] < b[2]; });
    vector<ConvexHullTrickAddMonotone<ll, true>> dp(T + 1);
    dp[0].add_line(0, 0);
    ll ans = 0;
    for (const auto& arr : s) {
        ll t = arr[0], p = arr[1], f = arr[2];
        rrep (i, T + 1) {
            if (dp[i].empty()) continue;
            if (i + t > T) continue;
            ll val = p + dp[i].get_min(f);
            if (i != 0) val -= f * f;
            chmax(ans, val);
            dp[i + t].add_line(2 * f, val - f * f);
        }
    }
    cout << ans << endl;
}
accuracy: 1
time_ms: 620
memory_kb: 9824
final_rank: 13

code_snippet: #line 1 "test/aoj/other/2725-CHT.test.cpp"
#define PROBLEM "https://onlinejudge.u-aizu.ac.jp/problems/2725"
#line 2 "other/template.hpp"

#include<bits/stdc++.h>

#ifndef __COUNTER__
#define __COUNTER__ __LINE__
#endif

#define REP_SELECTER(a, b, c, d, e, ...) e
#define REP1_0(b, c) REP1_1(b, c)
#define REP1_1(b, c) for (ll REP_COUNTER_ ## c = 0; REP_COUNTER_ ## c < (ll)(b); ++ REP_COUNTER_ ## c)
#define REP1(b) REP1_0(b, __COUNTER__)
#define REP2(i, b) for (ll i = 0; i < (ll)(b); ++i)
#define REP3(i, a, b) for (ll i = (ll)(a); i < (ll)(b); ++i)
#define REP4(i, a, b, c) for (ll i = (ll)(a); i < (ll)(b); i += (ll)(c))
#define rep(...) REP_SELECTER(__VA_ARGS__, REP4, REP3, REP2, REP1) (__VA_ARGS__)
#define RREP2(i, a) for (ll i = (ll)(a) - 1; i >= 0; --i)
#define RREP3(i, a, b) for (ll i = (ll)(a) - 1; i >= (ll)(b); --i)
#define RREP4(i, a, b, c) for (ll i = (ll)(a) - 1; i >= (ll)(b); i -= (ll)(c))
#define rrep(...) REP_SELECTER(__VA_ARGS__, RREP4, RREP3, RREP2) (__VA_ARGS__)
#define REPS2(i, b) for (ll i = 1; i <= (ll)(b); ++i)
#define REPS3(i, a, b) for (ll i = (ll)(a) + 1; i <= (ll)(b); ++i)
#define REPS4(i, a, b, c) for (ll i = (ll)(a) + 1; i <= (ll)(b); i += (ll)(c))
#define reps(...) REP_SELECTER(__VA_ARGS__, REPS4, REPS3, REPS2) (__VA_ARGS__)
#define RREPS2(i, a) for (ll i = (ll)(a); i > 0; --i)
#define RREPS3(i, a, b) for (ll i = (ll)(a); i > (ll)(b); --i)
#define RREPS4(i, a, b, c) for (ll i = (ll)(a); i > (ll)(b); i -= (ll)(c))
#define rreps(...) REP_SELECTER(__VA_ARGS__, RREPS4, RREPS3, RREPS2) (__VA_ARGS__)

#define all(v) (v).begin(), (v).end()

#if __cplusplus >= 201402L
#define CONSTEXPR constexpr
#else
#define CONSTEXPR
#endif

#ifdef __cpp_if_constexpr
#define IF_CONSTEXPR constexpr
#else
#define IF_CONSTEXPR
#endif

using ll = long long;
using ull = unsigned long long;
using ld = long double;
using PLL = std::pair<ll, ll>;
template<class T> using prique = std::priority_queue<T, std::vector<T>, std::greater<T>>;

template<class T> class infinity {
  public:
    static constexpr T value = std::numeric_limits<T>::max() / 2;
    static constexpr T mvalue = std::numeric_limits<T>::min() / 2;
    static constexpr T max = std::numeric_limits<T>::max();
    static constexpr T min = std::numeric_limits<T>::min();
};

#if __cplusplus <= 201402L
template<class T> constexpr T infinity<T>::value;
template<class T> constexpr T infinity<T>::mvalue;
template<class T> constexpr T infinity<T>::max;
template<class T> constexpr T infinity<T>::min;
#endif

#if __cplusplus >= 201402L
template<class T> constexpr T INF = infinity<T>::value;
#endif

constexpr ll inf = infinity<ll>::value;
constexpr ld EPS = 1e-8;
constexpr ld PI = 3.1415926535897932384626;

template<class T, class U> std::ostream& operator<<(std::ostream& ost, const std::pair<T, U>& p) {
    return ost << p.first << ' ' << p.second;
}
template<class T, class U> std::istream& operator>>(std::istream& ist, std::pair<T, U>& p) {
    return ist >> p.first >> p.second;
}

template<class Container,
        typename std::enable_if<!std::is_same<Container, std::string>::value>::type* = nullptr>
auto operator<<(std::ostream& ost, const Container& cont)
        -> decltype(cont.begin(), cont.end(), ost)
{
    for (auto itr = cont.begin(); itr != cont.end(); ++itr) {
        if (itr != cont.begin()) ost << ' ';
        ost << *itr;
    }
    return ost;
}
template<class Container,
        typename std::enable_if<!std::is_same<Container, std::string>::value>::type* = nullptr>
auto operator>>(std::istream& ist, Container& cont)
        -> decltype(cont.begin(), cont.end(), ist)
{
    for (auto itr = cont.begin(); itr != cont.end(); ++itr) ist >> *itr;
    return ist;
}

template<class T, class U> inline constexpr bool chmin(T &a, const U &b) noexcept {
    return a > b ? a = b, true : false;
}
template<class T, class U> inline constexpr bool chmax(T &a, const U &b) noexcept {
    return a < b ? a = b, true : false;
}

inline CONSTEXPR ll gcd(ll a, ll b) noexcept {
    while (b) {
        const ll c = a;
        a = b;
        b = c % b;
    }
    return a;
}
inline CONSTEXPR ll lcm(ll a, ll b) noexcept {
    return a / gcd(a, b) * b;
}

inline CONSTEXPR bool is_prime(ll N) noexcept {
    if (N <= 1) return false;
    for (ll i = 2; i * i <= N; ++i) {
        if (N % i == 0) return false;
    }
    return true;
}
inline std::vector<ll> prime_factor(ll N) noexcept {
    std::vector<ll> res;
    for (ll i = 2; i * i <= N; ++i) {
        while (N % i == 0) {
            res.push_back(i);
            N /= i;
        }
    }
    if (N != 1) res.push_back(N);
    return res;
}

inline CONSTEXPR ll my_pow(ll a, ll b) noexcept {
    ll res = 1;
    while (b) {
        if (b & 1) res *= a;
        b >>= 1;
        a *= a;
    }
    return res;
}
inline CONSTEXPR ll mod_pow(ll a, ll b, ll mod) noexcept {
    a %= mod;
    ll res = 1;
    while (b) {
        if (b & 1) (res *= a) %= mod;
        b >>= 1;
        (a *= a) %= mod;
    }
    return res;
}

PLL extGCD(ll a, ll b) noexcept {
    if (b == 0) return PLL{1, 0};
    PLL p = extGCD(b, a % b);
    std::swap(p.first, p.second);
    p.second -= p.first * (a / b);
    if (p.first < 0) {
        p.first += b;
        p.second -= a;
    }
    return p;
}
ll mod_inv(ll a, ll mod) noexcept {
    const PLL p = extGCD(a, mod);
    assert(p.first * a + p.second * mod == 1);
    return p.first;
}
PLL ChineseRemainder(ll b1, ll m1, ll b2, ll m2) noexcept {
    const PLL p = extGCD(m1, m2);
    const ll g = p.first * m1 + p.second * m2;
    const ll l = m1 / g * m2;
    if ((b2 - b1) % g != 0) return PLL{-1, -1};
    const ll x = (b2 - b1) / g * p.first % (m2 / g);
    return {(x * m1 + b1 + l) % l, l};
}
PLL ChineseRemainders(const std::vector<ll>& b, const std::vector<ll>& m) noexcept {
    PLL res{0, 1};
    rep (i, b.size()) {
        res = ChineseRemainder(res.first, res.second, b[i], m[i]);
        if (res.first == -1) return res;
    }
    return res;
}

template<class F> class RecLambda {
  private:
    F f;
  public:
    explicit constexpr RecLambda(F&& f_) : f(std::forward<F>(f_)) {}
    template<class... Args> constexpr auto operator()(Args&&... args) const
            -> decltype(f(*this, std::forward<Args>(args)...)) {
        return f(*this, std::forward<Args>(args)...);
    }
};

template<class F> inline constexpr RecLambda<F> rec_lambda(F&& f) {
    return RecLambda<F>(std::forward<F>(f));
}

template<class Head, class... Tails> struct multi_dim_vector {
    using type = std::vector<typename multi_dim_vector<Tails...>::type>;
};
template<class T> struct multi_dim_vector<T> {
    using type = T;
};

template<class T, class Arg> constexpr std::vector<T> make_vec(int n, Arg&& arg) {
    return std::vector<T>(n, std::forward<Arg>(arg));
}
template<class T, class... Args>
constexpr typename multi_dim_vector<Args..., T>::type make_vec(int n, Args&&... args) {
    return typename multi_dim_vector<Args..., T>::type (n, make_vec<T>(std::forward<Args>(args)...));
}

inline CONSTEXPR int popcnt(ull x) {
#if __cplusplus >= 202002L
    return std::popcount(x);
#endif
    x = (x & 0x5555555555555555) + ((x >> 1 ) & 0x5555555555555555);
    x = (x & 0x3333333333333333) + ((x >> 2 ) & 0x3333333333333333);
    x = (x & 0x0f0f0f0f0f0f0f0f) + ((x >> 4 ) & 0x0f0f0f0f0f0f0f0f);
    x = (x & 0x00ff00ff00ff00ff) + ((x >> 8 ) & 0x00ff00ff00ff00ff);
    x = (x & 0x0000ffff0000ffff) + ((x >> 16) & 0x0000ffff0000ffff);
    return (x & 0x00000000ffffffff) + ((x >> 32) & 0x00000000ffffffff);
}

template<class T> class presser : public std::vector<T> {
  private:
    using Base = std::vector<T>;
  public:
    using Base::Base;
    presser(const std::vector<T>& vec) : Base(vec) {}
    void push(const std::vector<T>& vec) {
        int n = this->size();
        this->resize(n + vec.size());
        std::copy(all(vec), this->begin() + n);
    }
    int build() {
        std::sort(this->begin(), this->end());
        this->erase(std::unique(this->begin(), this->end()), this->end());
        return this->size();
    }
    int get_index(const T& val) const {
        return static_cast<int>(std::lower_bound(this->begin(), this->end(), val) - this->begin());
    }
    std::vector<int> pressed(const std::vector<T>& vec) const {
        std::vector<int> res(vec.size());
        rep (i, vec.size()) res[i] = this->get_index(vec[i]);
        return res;
    }
    void press(std::vector<T>& vec) const {
        static_assert(std::is_integral<T>::value, "cannot convert from int type");
        rep (i, vec.size()) vec[i] = this->get_index(vec[i]);
    }
};
#line 2 "data-struct/cht/ConvexHullTrickAddMonotone.hpp"

#line 4 "data-struct/cht/ConvexHullTrickAddMonotone.hpp"

template<class T = ll, bool is_max = false> class ConvexHullTrickAddMonotone {
  protected:
    struct Line {
        T a, b;
        bool is_query;
        mutable const Line* nxt;
        T get(T x) const { return a * x + b; }
        Line() = default;
        Line(T a, T b, bool i = false) : a(a), b(b), is_query(i), nxt(nullptr) {}
        friend bool operator<(const Line& lhs, const Line& rhs) {
            assert(!lhs.is_query || !rhs.is_query);
            if (lhs.is_query) {
                if (rhs.nxt == nullptr) return true;
                return rhs.get(lhs.a) < rhs.nxt->get(lhs.a);
            }
            if (rhs.is_query) {
                if (lhs.nxt == nullptr) return false;
                return lhs.get(rhs.a) > lhs.nxt->get(rhs.a);
            }
            return lhs.a == rhs.a ? lhs.b < rhs.b : lhs.a < rhs.a;
        }
    };
    std::deque<Line> que;
    bool is_necessary(const typename std::deque<Line>::iterator& itr) {
        if (itr == que.begin() || itr == prev(que.end())) return true;
        if (itr->a == prev(itr)->a) return itr->b < prev(itr)->b;
        if (itr->a == next(itr)->a) return itr->b < next(itr)->b;
        return (__int128_t)(itr->b - prev(itr)->b) * (next(itr)->a - itr->a)
            <  (__int128_t)(itr->b - next(itr)->b) * (prev(itr)->a - itr->a);
    }
  public:
    ConvexHullTrickAddMonotone() = default;
    void add_line(T a, T b) {
        if IF_CONSTEXPR (is_max) a = - a, b = - b;
        typename std::deque<Line>::iterator itr;
        if (que.empty() || que.back().a <= a) {
            que.push_back(Line{a, b});
            itr = prev(que.end());
        }
        else {
            assert(a <= que.front().a);
            que.push_front(Line{a, b});
            itr = que.begin();
        }
        if (!is_necessary(itr)) {
            que.erase(itr);
            return;
        }
        while (itr != que.begin() && !is_necessary(prev(itr))) {
            que.pop_back(); que.pop_back();
            que.push_back(Line{a, b});
            itr = prev(que.end());
        }
        while (itr != prev(que.end()) && !is_necessary(next(itr))) {
            que.pop_front(); que.pop_front();
            que.push_front(Line{a, b});
            itr = que.begin();
        }
        if (itr != que.begin()) prev(itr)->nxt = &*itr;
        if (itr != prev(que.end())) itr->nxt = &*next(itr);
        else itr->nxt = nullptr;
    }
    T get_min(T x) const {
        auto itr = lower_bound(que.begin(), que.end(), Line{x, 0, true});
        if IF_CONSTEXPR (is_max) return - itr->get(x);
        return itr->get(x);
    }
    T inc_get_min(T x) {
        while (que.size() > 1 && que.begin()->get(x) > next(que.begin())->get(x)) que.pop_front();
        if IF_CONSTEXPR (is_max) return - que.front().get(x);
        return que.front().get(x);
    }
    T dec_get_min(T x) {
        while (que.size() > 1 && prev(que.end())->get(x) > prev(que.end(), 2)->get(x)) que.pop_back();
        if IF_CONSTEXPR (is_max) return - que.back().get(x);
        return que.back().get(x);
    }
    bool empty() const {
        return que.empty();
    }
};

/**
 * @brief ConvexHullTrickAddMonotone
 * @docs docs/ConvexHullTrickAddMonotone.md
 */
#line 4 "test/aoj/other/2725-CHT.test.cpp"
using namespace std;
int main() {
    int N, T; cin >> N >> T;
    vector<array<ll, 3>> s(N); cin >> s;
    sort(s.begin(), s.end(), [](auto a, auto b) -> bool { return a[2] < b[2]; });
    vector<ConvexHullTrickAddMonotone<ll, true>> dp(T + 1);
    dp[0].add_line(0, 0);
    ll ans = 0;
    for (const auto& arr : s) {
        ll t = arr[0], p = arr[1], f = arr[2];
        rrep (i, T + 1) {
            if (dp[i].empty()) continue;
            if (i + t > T) continue;
            ll val = p + dp[i].inc_get_min(f);
            if (i != 0) val -= f * f;
            chmax(ans, val);
            dp[i + t].add_line(2 * f, val - f * f);
        }
    }
    cout << ans << endl;
}
accuracy: 1
time_ms: 300
memory_kb: 9676
final_rank: 10

code_snippet: #pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<unordered_set>
#include<utility>
#include<cassert>
#include<complex>
#include<numeric>
#include<array>
#include<chrono>
using namespace std;

//#define int long long
typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
constexpr ll mod = 998244353;
const ll INF = mod * mod;
typedef pair<int, int>P;

#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
#define all(v) (v).begin(),(v).end()
typedef pair<ll, ll> LP;

template<typename T>
void chmin(T& a, T b) {
	a = min(a, b);
}
template<typename T>
void chmax(T& a, T b) {
	a = max(a, b);
}
template<typename T>
void cinarray(vector<T>& v) {
	rep(i, v.size())cin >> v[i];
}
template<typename T>
void coutarray(vector<T>& v) {
	rep(i, v.size()) {
		if (i > 0)cout << " "; cout << v[i];
	}
	cout << "\n";
}
ll mod_pow(ll x, ll n, ll m = mod) {
	if (n < 0) {
		ll res = mod_pow(x, -n, m);
		return mod_pow(res, m - 2, m);
	}
	if (abs(x) >= m)x %= m;
	if (x < 0)x += m;
	if (x == 0)return 0;
	ll res = 1;
	while (n) {
		if (n & 1)res = res * x % m;
		x = x * x % m; n >>= 1;
	}
	return res;
}
struct modint {
	int n;
	modint() :n(0) { ; }
	modint(ll m) {
		if (m < 0 || mod <= m) {
			m %= mod; if (m < 0)m += mod;
		}
		n = m;
	}
	operator int() { return n; }
};
bool operator==(modint a, modint b) { return a.n == b.n; }
modint operator+=(modint& a, modint b) { a.n += b.n; if (a.n >= mod)a.n -= mod; return a; }
modint operator-=(modint& a, modint b) { a.n -= b.n; if (a.n < 0)a.n += mod; return a; }
modint operator*=(modint& a, modint b) { a.n = ((ll)a.n * b.n) % mod; return a; }
modint operator+(modint a, modint b) { return a += b; }
modint operator-(modint a, modint b) { return a -= b; }
modint operator*(modint a, modint b) { return a *= b; }
modint operator^(modint a, ll n) {
	if (n == 0)return modint(1);
	modint res = (a * a) ^ (n / 2);
	if (n % 2)res = res * a;
	return res;
}

ll inv(ll a, ll p) {
	return (a == 1 ? 1 : (1 - p * inv(p % a, a)) / a + p);
}
modint operator/(modint a, modint b) { return a * modint(inv(b, mod)); }
modint operator/=(modint& a, modint b) { a = a / b; return a; }
const int max_n = 1 << 20;
modint fact[max_n], factinv[max_n];
void init_f() {
	fact[0] = modint(1);
	for (int i = 0; i < max_n - 1; i++) {
		fact[i + 1] = fact[i] * modint(i + 1);
	}
	factinv[max_n - 1] = modint(1) / fact[max_n - 1];
	for (int i = max_n - 2; i >= 0; i--) {
		factinv[i] = factinv[i + 1] * modint(i + 1);
	}
}
modint comb(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[b] * factinv[a - b];
}
modint combP(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[a - b];
}

ll gcd(ll a, ll b) {
	a = abs(a); b = abs(b);
	if (a < b)swap(a, b);
	while (b) {
		ll r = a % b; a = b; b = r;
	}
	return a;
}
typedef long double ld;
typedef pair<ld, ld> LDP;
const ld eps = 1e-8;
const ld pi = acosl(-1.0);
int dx[4] = { 1,0,-1,0 };
int dy[4] = { 0,1,0,-1 };

using mP = pair<modint, modint>;
//-----------------------------------

struct CHT {
	vector<LP> v;
	vector<LP> memo;
	int l = 0;
	bool check(LP a, LP b, LP c) {
		//return __int128(b.first - a.first) * __int128(c.second - b.second) >= __int128(b.second - a.second) * __int128(c.first - b.first);
		return (b.first - a.first) * (c.second - b.second) >= (b.second - a.second) * (c.first - b.first);
	}
	//一気に作る
	void build(vector<LP> a) {
		l = 0;
		sort(a.begin(), a.end());
		per(i, (int)a.size()) {
			while (v.size() >= 2 && check(v[v.size() - 2], v[v.size() - 1], a[i]))v.pop_back();
			v.push_back(a[i]);
		}
	}
	//傾きが小さい順に追加して作る
	void build() {
		sort(all(memo));
		per(i, (int)memo.size()) {
			while (v.size() >= 2 && check(v[v.size() - 2], v[v.size() - 1], memo[i]))v.pop_back();
			v.push_back(memo[i]);
		}
		memo.clear();
	}
	void subadd(LP a) {
		memo.push_back(a);
	}
	void add(LP a) {
		if (v.size() && v.back().first == a.first && v.back().second < a.second)return;
		while (v.size() >= 2 && check(v[v.size() - 2], v[v.size() - 1], a))v.pop_back();
		v.push_back(a);
		l = min(l, (int)v.size() - 1);
	}
	//xは単調増加
	ll f(LP a, ll x) {
		return a.first * x + a.second;
	}
	ll query(ll x) {
		if (l >= v.size())return INF;
		while (l + 1 < v.size() && f(v[l], x) > f(v[l + 1], x))l++;
		return f(v[l], x);
	}
};
void solve() {
	int n, T; cin >> n >> T;
	vector<int> t(n), p(n), f(n);
	rep(i, n)cin >> t[i] >> p[i] >> f[i];
	vector<P> vp;
	rep(i, n)vp.push_back({ f[i],i });
	sort(all(vp));
	vector<CHT> cht(T + 1);
	cht[0].add({ 0,0 });
	ll ans = 0;
	rep(i, vp.size()) {
		int id = vp[i].second;
		per(j, T + 1) {
			if (j + t[id] <= T) {
				ll val = -cht[j].query(f[id]);
				if (val > -INF) {
					val -= f[id] * f[id];
					val += p[id];
					if (j == 0)val = p[id];
					chmax(ans, val);
					cht[j + t[id]].add({ -2 * f[id],f[id] * f[id] - val });
				}
			}
		}
	}
	cout << ans << "\n";
}


signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(10);
	//init_f();
	//init();
	//while(true)
	//expr();
	//int t; cin >> t; rep(i, t)
	solve();
	return 0;
}
accuracy: 1
time_ms: 120
memory_kb: 13860
final_rank: 4

code_snippet: #pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<unordered_set>
#include<utility>
#include<cassert>
#include<complex>
#include<numeric>
#include<array>
#include<chrono>
using namespace std;

//#define int long long
typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
constexpr ll mod = 998244353;
const ll INF = mod * mod;
typedef pair<int, int>P;

#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
#define all(v) (v).begin(),(v).end()
typedef pair<ll, ll> LP;

template<typename T>
void chmin(T& a, T b) {
	a = min(a, b);
}
template<typename T>
void chmax(T& a, T b) {
	a = max(a, b);
}
template<typename T>
void cinarray(vector<T>& v) {
	rep(i, v.size())cin >> v[i];
}
template<typename T>
void coutarray(vector<T>& v) {
	rep(i, v.size()) {
		if (i > 0)cout << " "; cout << v[i];
	}
	cout << "\n";
}
ll mod_pow(ll x, ll n, ll m = mod) {
	if (n < 0) {
		ll res = mod_pow(x, -n, m);
		return mod_pow(res, m - 2, m);
	}
	if (abs(x) >= m)x %= m;
	if (x < 0)x += m;
	if (x == 0)return 0;
	ll res = 1;
	while (n) {
		if (n & 1)res = res * x % m;
		x = x * x % m; n >>= 1;
	}
	return res;
}
struct modint {
	int n;
	modint() :n(0) { ; }
	modint(ll m) {
		if (m < 0 || mod <= m) {
			m %= mod; if (m < 0)m += mod;
		}
		n = m;
	}
	operator int() { return n; }
};
bool operator==(modint a, modint b) { return a.n == b.n; }
modint operator+=(modint& a, modint b) { a.n += b.n; if (a.n >= mod)a.n -= mod; return a; }
modint operator-=(modint& a, modint b) { a.n -= b.n; if (a.n < 0)a.n += mod; return a; }
modint operator*=(modint& a, modint b) { a.n = ((ll)a.n * b.n) % mod; return a; }
modint operator+(modint a, modint b) { return a += b; }
modint operator-(modint a, modint b) { return a -= b; }
modint operator*(modint a, modint b) { return a *= b; }
modint operator^(modint a, ll n) {
	if (n == 0)return modint(1);
	modint res = (a * a) ^ (n / 2);
	if (n % 2)res = res * a;
	return res;
}

ll inv(ll a, ll p) {
	return (a == 1 ? 1 : (1 - p * inv(p % a, a)) / a + p);
}
modint operator/(modint a, modint b) { return a * modint(inv(b, mod)); }
modint operator/=(modint& a, modint b) { a = a / b; return a; }
const int max_n = 1 << 20;
modint fact[max_n], factinv[max_n];
void init_f() {
	fact[0] = modint(1);
	for (int i = 0; i < max_n - 1; i++) {
		fact[i + 1] = fact[i] * modint(i + 1);
	}
	factinv[max_n - 1] = modint(1) / fact[max_n - 1];
	for (int i = max_n - 2; i >= 0; i--) {
		factinv[i] = factinv[i + 1] * modint(i + 1);
	}
}
modint comb(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[b] * factinv[a - b];
}
modint combP(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[a - b];
}

ll gcd(ll a, ll b) {
	a = abs(a); b = abs(b);
	if (a < b)swap(a, b);
	while (b) {
		ll r = a % b; a = b; b = r;
	}
	return a;
}
typedef long double ld;
typedef pair<ld, ld> LDP;
const ld eps = 1e-8;
const ld pi = acosl(-1.0);
int dx[4] = { 1,0,-1,0 };
int dy[4] = { 0,1,0,-1 };

using mP = pair<modint, modint>;
//-----------------------------------

struct CHT {
	vector<LP> v;
	vector<LP> memo;
	int l = 0;
	bool check(LP a, LP b, LP c) {
		return __int128(b.first - a.first) * __int128(c.second - b.second) >= __int128(b.second - a.second) * __int128(c.first - b.first);
		//return (b.first - a.first) * (c.second - b.second) >= (b.second - a.second) * (c.first - b.first);
	}
	//一気に作る
	void build(vector<LP> a) {
		l = 0;
		sort(a.begin(), a.end());
		per(i, (int)a.size()) {
			while (v.size() >= 2 && check(v[v.size() - 2], v[v.size() - 1], a[i]))v.pop_back();
			v.push_back(a[i]);
		}
	}
	//傾きが小さい順に追加して作る
	void build() {
		sort(all(memo));
		per(i, (int)memo.size()) {
			while (v.size() >= 2 && check(v[v.size() - 2], v[v.size() - 1], memo[i]))v.pop_back();
			v.push_back(memo[i]);
		}
		memo.clear();
	}
	void subadd(LP a) {
		memo.push_back(a);
	}
	void add(LP a) {
		while (v.size() >= 2 && check(v[v.size() - 2], v[v.size() - 1], a))v.pop_back();
		v.push_back(a);
		l = min(l, (int)v.size() - 1);
	}
	//xは単調増加
	ll f(LP a, ll x) {
		return a.first * x + a.second;
	}
	ll query(ll x) {
		if (l >= v.size())return INF;
		while (l + 1 < v.size() && f(v[l], x) > f(v[l + 1], x))l++;
		return f(v[l], x);
	}
};
void solve() {
	int n, T; cin >> n >> T;
	vector<int> t(n), p(n), f(n);
	rep(i, n)cin >> t[i] >> p[i] >> f[i];
	vector<P> vp;
	rep(i, n)vp.push_back({ f[i],i });
	sort(all(vp));
	vector<CHT> cht(T + 1);
	cht[0].add({ 0,0 });
	ll ans = 0;
	rep(i, vp.size()) {
		int id = vp[i].second;
		per(j, T + 1) {
			if (j + t[id] <= T) {
				ll val = -cht[j].query(f[id]);
				if (val > -INF) {
					val -= f[id] * f[id];
					val += p[id];
					if (j == 0)val = p[id];
					chmax(ans, val);
					cht[j + t[id]].add({ -2 * f[id],f[id] * f[id] - val });
				}
			}
		}
	}
	cout << ans << "\n";
}


signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(10);
	//init_f();
	//init();
	//while(true)
	//expr();
	//int t; cin >> t; rep(i, t)
	solve();
	return 0;
}
accuracy: 0.9873417721518988
time_ms: 140
memory_kb: 13904
final_rank: 20

code_snippet: #pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<unordered_set>
#include<utility>
#include<cassert>
#include<complex>
#include<numeric>
#include<array>
#include<chrono>
using namespace std;

//#define int long long
typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
constexpr ll mod = 998244353;
const ll INF = mod * mod;
typedef pair<int, int>P;

#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
#define all(v) (v).begin(),(v).end()
typedef pair<ll, ll> LP;

template<typename T>
void chmin(T& a, T b) {
	a = min(a, b);
}
template<typename T>
void chmax(T& a, T b) {
	a = max(a, b);
}
template<typename T>
void cinarray(vector<T>& v) {
	rep(i, v.size())cin >> v[i];
}
template<typename T>
void coutarray(vector<T>& v) {
	rep(i, v.size()) {
		if (i > 0)cout << " "; cout << v[i];
	}
	cout << "\n";
}
ll mod_pow(ll x, ll n, ll m = mod) {
	if (n < 0) {
		ll res = mod_pow(x, -n, m);
		return mod_pow(res, m - 2, m);
	}
	if (abs(x) >= m)x %= m;
	if (x < 0)x += m;
	if (x == 0)return 0;
	ll res = 1;
	while (n) {
		if (n & 1)res = res * x % m;
		x = x * x % m; n >>= 1;
	}
	return res;
}
struct modint {
	int n;
	modint() :n(0) { ; }
	modint(ll m) {
		if (m < 0 || mod <= m) {
			m %= mod; if (m < 0)m += mod;
		}
		n = m;
	}
	operator int() { return n; }
};
bool operator==(modint a, modint b) { return a.n == b.n; }
modint operator+=(modint& a, modint b) { a.n += b.n; if (a.n >= mod)a.n -= mod; return a; }
modint operator-=(modint& a, modint b) { a.n -= b.n; if (a.n < 0)a.n += mod; return a; }
modint operator*=(modint& a, modint b) { a.n = ((ll)a.n * b.n) % mod; return a; }
modint operator+(modint a, modint b) { return a += b; }
modint operator-(modint a, modint b) { return a -= b; }
modint operator*(modint a, modint b) { return a *= b; }
modint operator^(modint a, ll n) {
	if (n == 0)return modint(1);
	modint res = (a * a) ^ (n / 2);
	if (n % 2)res = res * a;
	return res;
}

ll inv(ll a, ll p) {
	return (a == 1 ? 1 : (1 - p * inv(p % a, a)) / a + p);
}
modint operator/(modint a, modint b) { return a * modint(inv(b, mod)); }
modint operator/=(modint& a, modint b) { a = a / b; return a; }
const int max_n = 1 << 20;
modint fact[max_n], factinv[max_n];
void init_f() {
	fact[0] = modint(1);
	for (int i = 0; i < max_n - 1; i++) {
		fact[i + 1] = fact[i] * modint(i + 1);
	}
	factinv[max_n - 1] = modint(1) / fact[max_n - 1];
	for (int i = max_n - 2; i >= 0; i--) {
		factinv[i] = factinv[i + 1] * modint(i + 1);
	}
}
modint comb(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[b] * factinv[a - b];
}
modint combP(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[a - b];
}

ll gcd(ll a, ll b) {
	a = abs(a); b = abs(b);
	if (a < b)swap(a, b);
	while (b) {
		ll r = a % b; a = b; b = r;
	}
	return a;
}
typedef long double ld;
typedef pair<ld, ld> LDP;
const ld eps = 1e-8;
const ld pi = acosl(-1.0);
int dx[4] = { 1,0,-1,0 };
int dy[4] = { 0,1,0,-1 };

using mP = pair<modint, modint>;
//-----------------------------------

struct CHT {
	vector<LP> v;
	vector<LP> memo;
	int l = 0;
	bool check(LP a, LP b, LP c) {
		//return __int128(b.first - a.first) * __int128(c.second - b.second) >= __int128(b.second - a.second) * __int128(c.first - b.first);
		return (b.first - a.first) * (c.second - b.second) >= (b.second - a.second) * (c.first - b.first);
	}
	//一気に作る
	void build(vector<LP> a) {
		l = 0;
		sort(a.begin(), a.end());
		per(i, (int)a.size()) {
			while (v.size() >= 2 && check(v[v.size() - 2], v[v.size() - 1], a[i]))v.pop_back();
			v.push_back(a[i]);
		}
	}
	//傾きが小さい順に追加して作る
	void build() {
		sort(all(memo));
		per(i, (int)memo.size()) {
			while (v.size() >= 2 && check(v[v.size() - 2], v[v.size() - 1], memo[i]))v.pop_back();
			v.push_back(memo[i]);
		}
		memo.clear();
	}
	void subadd(LP a) {
		memo.push_back(a);
	}
	void add(LP a) {
		while (v.size() >= 2 && check(v[v.size() - 2], v[v.size() - 1], a))v.pop_back();
		v.push_back(a);
		l = min(l, (int)v.size() - 1);
	}
	//xは単調増加
	ll f(LP a, ll x) {
		return a.first * x + a.second;
	}
	ll query(ll x) {
		if (l >= v.size())return INF;
		while (l + 1 < v.size() && f(v[l], x) > f(v[l + 1], x))l++;
		return f(v[l], x);
	}
};
void solve() {
	int n, T; cin >> n >> T;
	vector<int> t(n), p(n), f(n);
	rep(i, n)cin >> t[i] >> p[i] >> f[i];
	vector<P> vp;
	rep(i, n)vp.push_back({ f[i],i });
	sort(all(vp));
	vector<CHT> cht(T + 1);
	cht[0].add({ 0,0 });
	ll ans = 0;
	rep(i, vp.size()) {
		int id = vp[i].second;
		per(j, T + 1) {
			if (j + t[id] <= T) {
				ll val = -cht[j].query(f[id]);
				if (val > -INF) {
					val -= f[id] * f[id];
					val += p[id];
					if (j == 0)val = p[id];
					chmax(ans, val);
					cht[j + t[id]].add({ -2 * f[id],f[id] * f[id] - val });
				}
			}
		}
	}
	cout << ans << "\n";
}


signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(10);
	//init_f();
	//init();
	//while(true)
	//expr();
	//int t; cin >> t; rep(i, t)
	solve();
	return 0;
}
accuracy: 0.9873417721518988
time_ms: 130
memory_kb: 13876
final_rank: 19

code_snippet: // verification-helper: PROBLEM http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2725

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

#define call_from_test
template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}

template<typename ...Ts>
decltype(auto) zip(vector<Ts>... args){
  vector<decltype(make_tuple(args[0]...))> res;
  int n=min({args.size()...});
  res.reserve(n);
  for(int i=0;i<n;i++) res.emplace_back(args[i]...);
  return res;
}

enum Objective{
  MAXIMIZE = +1,
  MINIMIZE = -1,
};

template<typename T>
struct Line {
  mutable T k,m,p;
  bool operator<(const Line&o)const{return k<o.k;}
  bool operator<(T x)const{return p<x;}
};

template<typename T> T lc_inf(){return numeric_limits<T>::max();}
template<> double lc_inf<double>(){return 1/.0;}

template<typename T> T lc_div(T a,T b){return a/b-((a^b)<0 and a%b);}
template<> double lc_div(double a,double b){return a/b;};

template<typename T, Objective objective>
struct LineContainer : multiset<Line<T>, less<>>{
  using super = multiset<Line<T>, less<>>;
  using super::begin,super::end,super::insert,super::erase;
  using super::empty,super::lower_bound;
  const T inf = lc_inf<T>();
  bool insect(typename super::iterator x,typename super::iterator y){
    if(y==end()) return x->p=inf,false;
    if(x->k==y->k) x->p=(x->m>y->m?inf:-inf);
    else x->p=lc_div(y->m-x->m,x->k-y->k);
    return x->p>=y->p;
  }
  void add(T k,T m){
    auto z=insert({k*objective,m*objective,0}),y=z++,x=y;
    while(insect(y,z)) z=erase(z);
    if(x!=begin() and insect(--x,y)) insect(x,y=erase(y));
    while((y=x)!=begin() and (--x)->p>=y->p) insect(x,erase(y));
  }
  T query(T x){
    assert(!empty());
    auto l=*lower_bound(x);
    return (l.k*x+l.m)*objective;
  }
};
template<typename T>
using MinLineContainer = LineContainer<T, Objective::MINIMIZE>;
template<typename T>
using MaxLineContainer = LineContainer<T, Objective::MAXIMIZE>;

#undef call_from_test

signed main(){
  cin.tie(0);
  ios::sync_with_stdio(0);
  using ll = long long;

  int n,x;
  cin>>n>>x;
  vector<ll> ts(n),ps(n),fs(n);
  for(int i=0;i<n;i++) cin>>ts[i]>>ps[i]>>fs[i];

  auto vt=zip(fs,ps,ts);
  sort(vt.begin(),vt.end());
  for(int i=0;i<n;i++) tie(fs[i],ps[i],ts[i])=vt[i];

  vector<MaxLineContainer<ll>> vh(x+1);

  ll ans=0;
  for(int i=0;i<n;i++){
    for(int j=x;j>ts[i];j--){
      if(vh[j-ts[i]].empty()) continue;
      ll val=vh[j-ts[i]].query(fs[i])+ps[i]-fs[i]*fs[i];
      vh[j].add(2*fs[i],val-fs[i]*fs[i]);
      chmax(ans,val);
    }
    vh[ts[i]].add(2*fs[i],ps[i]-fs[i]*fs[i]);
    chmax(ans,ps[i]);
  }

  cout<<ans<<endl;
  return 0;
}
accuracy: 1
time_ms: 1270
memory_kb: 9940
final_rank: 15

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

struct ConvexHullTrick_Line {
    mutable ll a, b, p;
    ConvexHullTrick_Line() = default;
    bool operator<(const ConvexHullTrick_Line& l) const { return a < l.a; }
    bool operator<(ll x) const { return p < x; }
};
template <bool ismin = false>
struct ConvexHullTrick : multiset<ConvexHullTrick_Line, less<>> {
    const ll INF = LLONG_MAX;
    ll div(ll a, ll b) { return a / b - ((a ^ b) < 0 && a % b); }
    ConvexHullTrick() = default;
    bool isect(iterator x, iterator y) {
        if (y == end()) {
            x->p = INF;
            return false;
        } else if (x->a == y->a) {
            x->p = (x->b > y->b ? INF : -INF);
        } else {
            x->p = div(y->b - x->b, x->a - y->a);
        }
        return x->p >= y->p;
    }
    void add(ll a, ll b) {
        if (ismin)
            a *= -1, b *= -1;
        auto z = insert({a, b, 0}), y = z++, x = y;
        while (isect(y, z))
            z = erase(z);
        if (x != begin() && isect(--x, y))
            isect(x, y = erase(y));
        while ((y = x) != begin() && (--x)->p >= y->p)
            isect(x, erase(y));
    }
    ll query(ll x) {
        assert(!empty());
        auto l = *lower_bound(x);
        auto ret = l.a * x + l.b;
        return ismin ? -ret : ret;
    }
};

int main() {
    struct Song {
        ll t, p, f;
    };
    ll N, T;
    cin >> N >> T;
    vector<Song> songs(N);
    for (auto&& s : songs) {
        ll t, p, f;
        cin >> t >> p >> f;
        s = {t, p, f};
    }
    sort(begin(songs), end(songs), [](const auto& x, const auto& y) { return x.f < y.f; });
    vector<ConvexHullTrick<false>> dp(T + 1);
    dp[0].add(0, 0);
    ll ans = 0;
    for (auto&& s : songs) {
        ll t = s.t, p = s.p, f = s.f;
        for (int len = T - t; len >= 0; len--) {
            if (dp[len].empty())
                continue;
            ll maine = dp[len].query(f) + p - f * f;
            if (len == 0)
                maine += f * f;
            ans = max(ans, maine);
            dp[len + t].add(2 * f, maine - f * f);
        }
    }
    cout << ans << endl;
}
accuracy: 1
time_ms: 1240
memory_kb: 9856
final_rank: 14

code_snippet: // verification-helper: PROBLEM http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2725

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

#define call_from_test

#ifndef call_from_test
#include <bits/stdc++.h>
using namespace std;
#endif
//BEGIN CUT HERE
template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}
//END CUT HERE
#ifndef call_from_test
signed main(){
  return 0;
}
#endif


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

//BEGIN CUT HERE
template<typename ...Ts>
decltype(auto) zip(vector<Ts>... args){
  vector<decltype(make_tuple(args[0]...))> res;
  int n=min({args.size()...});
  res.reserve(n);
  for(int i=0;i<n;i++) res.emplace_back(args[i]...);
  return res;
}
//END CUT HERE
#ifndef call_from_test
signed main(){
  vector<int> as({1,2,3});
  vector<string> bs({"a","b","c"});
  auto zs=zip(as,bs);
  for(auto [x,y]:zs) cout<<x<<" "<<y<<endl;
  return 0;
}
#endif

#ifndef call_from_test
#include<bits/stdc++.h>
using namespace std;
#endif
//BEGIN CUT HERE
enum Objective{
  MINIMIZE = +1,
  MAXIMIZE = -1,
};

template<typename T> struct Line {
  T k,m;
  T operator()(const T x)const{return k*x+m;}
};

template <typename T, Objective objective>
struct ConvexHullTrick : deque<Line<T>>{
  inline int sgn(T x){return x==0?0:(x<0?-1:1);}

  using D = long double;
  inline bool check(const Line<T> &a,const Line<T> &b,const Line<T> &c){
    if(b.m==a.m||c.m==b.m)
      return sgn(b.k-a.k)*sgn(c.m-b.m) >= sgn(c.k-b.k)*sgn(b.m-a.m);
    // return (b.k-a.k)*(c.m-b.m) >= (b.m-a.m)*(c.k-b.k);
    return
      D(b.k-a.k)*sgn(c.m-b.m)/D(abs(b.m-a.m)) >=
      D(c.k-b.k)*sgn(b.m-a.m)/D(abs(c.m-b.m));
  }

  using super = deque<Line<T>>;
  using super::empty,super::size,super::front,super::back;
  using super::emplace_front,super::emplace_back;
  using super::pop_front,super::pop_back;
  const Line<T> at(int i) const{return (*this)[i];}

  void add(T k_,T m_){
    Line<T> l({k_*objective,m_*objective});
    if(empty()){
      emplace_front(l);
      return;
    }
    if(front().k<=l.k){
      if(front().k==l.k){
        if(front().m<=l.m) return;
        pop_front();
      }
      while(size()>=2 and check(l,at(0),at(1))) pop_front();
      emplace_front(l);
    }else{
      assert(l.k<=back().k);
      if(back().k==l.k){
        if(back().m<=l.m) return;
        pop_back();
      }
      while(size()>=2 and check(at(size()-2),at(size()-1),l)) pop_back();
      emplace_back(l);
    }
  }

  T query(T x){
    assert(!empty());
    int l=-1,r=size()-1;
    while(l+1<r){
      int m=(l+r)>>1;
      if(at(m)(x)>=at(m+1)(x)) l=m;
      else r=m;
    }
    return at(r)(x)*objective;
  }

  T queryMonotoneInc(T x){
    assert(!empty());
    while(size()>=2 and at(0)(x)>=at(1)(x)) pop_front();
    return front()(x)*objective;
  }

  T queryMonotoneDec(T x){
    assert(!empty());
    while(size()>=2 and at(size()-1)(x)>=at(size()-2)(x)) pop_back();
    return back()(x)*objective;
  }
};
template<typename T>
using MinConvexHullTrick = ConvexHullTrick<T, Objective::MINIMIZE>;
template<typename T>
using MaxConvexHullTrick = ConvexHullTrick<T, Objective::MAXIMIZE>;
//END CUT HERE
#ifndef call_from_test
signed main(){
  return 0;
}
#endif

#undef call_from_test

signed main(){
  cin.tie(0);
  ios::sync_with_stdio(0);
  using ll = long long;

  int n,x;
  cin>>n>>x;
  vector<ll> ts(n),ps(n),fs(n);
  for(int i=0;i<n;i++) cin>>ts[i]>>ps[i]>>fs[i];

  auto vt=zip(fs,ps,ts);
  sort(vt.begin(),vt.end());
  for(int i=0;i<n;i++) tie(fs[i],ps[i],ts[i])=vt[i];

  vector<MaxConvexHullTrick<ll>> vh(x+1);

  ll ans=0;
  for(int i=0;i<n;i++){
    for(int j=x;j>ts[i];j--){
      if(vh[j-ts[i]].empty()) continue;
      ll val=vh[j-ts[i]].queryMonotoneInc(fs[i])+ps[i]-fs[i]*fs[i];
      vh[j].add(2*fs[i],val-fs[i]*fs[i]);
      chmax(ans,val);
    }
    vh[ts[i]].add(2*fs[i],ps[i]-fs[i]*fs[i]);
    chmax(ans,ps[i]);
  }

  cout<<ans<<endl;
  return 0;
}
accuracy: 1
time_ms: 220
memory_kb: 6708
final_rank: 9

code_snippet: // verification-helper: PROBLEM http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2725

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

#define call_from_test

#ifndef call_from_test
#include <bits/stdc++.h>
using namespace std;
#endif
//BEGIN CUT HERE
template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}
//END CUT HERE
#ifndef call_from_test
signed main(){
  return 0;
}
#endif


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

//BEGIN CUT HERE
template<typename ...Ts>
decltype(auto) zip(vector<Ts>... args){
  vector<decltype(make_tuple(args[0]...))> res;
  int n=min({args.size()...});
  res.reserve(n);
  for(int i=0;i<n;i++) res.emplace_back(args[i]...);
  return res;
}
//END CUT HERE
#ifndef call_from_test
signed main(){
  vector<int> as({1,2,3});
  vector<string> bs({"a","b","c"});
  auto zs=zip(as,bs);
  for(auto [x,y]:zs) cout<<x<<" "<<y<<endl;
  return 0;
}
#endif

#ifndef call_from_test
#include<bits/stdc++.h>
using namespace std;
#endif
//BEGIN CUT HERE
enum Objective{
  MINIMIZE = +1,
  MAXIMIZE = -1,
};

template<typename T> struct Line {T k,m;};

template <typename T, Objective objective>
struct ConvexHullTrick : deque<Line<T>>{
  inline int sgn(T x){return x==0?0:(x<0?-1:1);}

  using D = long double;
  inline bool check(const Line<T> &a,const Line<T> &b,const Line<T> &c){
    if(b.m==a.m||c.m==b.m)
      return sgn(b.k-a.k)*sgn(c.m-b.m) >= sgn(c.k-b.k)*sgn(b.m-a.m);
    // return (b.k-a.k)*(c.m-b.m) >= (b.m-a.m)*(c.k-b.k);
    return
      D(b.k-a.k)*sgn(c.m-b.m)/D(abs(b.m-a.m)) >=
      D(c.k-b.k)*sgn(b.m-a.m)/D(abs(c.m-b.m));
  }

  using super = deque<Line<T>>;
  using super::empty,super::size,super::front,super::back;
  using super::emplace_front,super::emplace_back;
  using super::pop_front,super::pop_back;
  const Line<T> at(int i) const{return (*this)[i];}

  void add(T k_,T m_){
    Line<T> l({k_*objective,m_*objective});
    if(empty()){
      emplace_front(l);
      return;
    }
    if(front().k<=l.k){
      if(front().k==l.k){
        if(front().m<=l.m) return;
        pop_front();
      }
      while(size()>=2 and check(l,at(0),at(1))) pop_front();
      emplace_front(l);
    }else{
      assert(l.k<=back().k);
      if(back().k==l.k){
        if(back().m<=l.m) return;
        pop_back();
      }
      while(size()>=2 and check(at(size()-2),at(size()-1),l)) pop_back();
      emplace_back(l);
    }
  }

  inline T getY(const Line<T> &a,const T &x){return a.k*x+a.m;}

  T query(T x){
    assert(!empty());
    int l=-1,r=size()-1;
    while(l+1<r){
      int m=(l+r)>>1;
      if(getY(at(m),x)>=getY(at(m+1),x)) l=m;
      else r=m;
    }
    return getY(at(r),x)*objective;
  }

  T queryMonotoneInc(T x){
    assert(!empty());
    while(size()>=2 and getY(at(0),x)>=getY(at(1),x)) pop_front();
    return getY(front(),x)*objective;
  }

  T queryMonotoneDec(T x){
    assert(!empty());
    while(size()>=2 and getY(at(size()-1),x)>=getY(at(size()-2),x)) pop_back();
    return getY(back(),x)*objective;
  }
};
template<typename T>
using MinConvexHullTrick = ConvexHullTrick<T, Objective::MINIMIZE>;
template<typename T>
using MaxConvexHullTrick = ConvexHullTrick<T, Objective::MAXIMIZE>;
//END CUT HERE
#ifndef call_from_test
signed main(){
  return 0;
}
#endif

#undef call_from_test

signed main(){
  cin.tie(0);
  ios::sync_with_stdio(0);
  using ll = long long;

  int n,x;
  cin>>n>>x;
  vector<ll> ts(n),ps(n),fs(n);
  for(int i=0;i<n;i++) cin>>ts[i]>>ps[i]>>fs[i];

  auto vt=zip(fs,ps,ts);
  sort(vt.begin(),vt.end());
  for(int i=0;i<n;i++) tie(fs[i],ps[i],ts[i])=vt[i];

  vector<MaxConvexHullTrick<ll>> vh(x+1);

  ll ans=0;
  for(int i=0;i<n;i++){
    for(int j=x;j>ts[i];j--){
      if(vh[j-ts[i]].empty()) continue;
      ll val=vh[j-ts[i]].queryMonotoneInc(fs[i])+ps[i]-fs[i]*fs[i];
      vh[j].add(2*fs[i],val-fs[i]*fs[i]);
      chmax(ans,val);
    }
    vh[ts[i]].add(2*fs[i],ps[i]-fs[i]*fs[i]);
    chmax(ans,ps[i]);
  }

  cout<<ans<<endl;
  return 0;
}
accuracy: 1
time_ms: 210
memory_kb: 6664
final_rank: 5

code_snippet: // verification-helper: PROBLEM http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2725

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

#define call_from_test

#ifndef call_from_test
#include <bits/stdc++.h>
using namespace std;
#endif
//BEGIN CUT HERE
template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}
//END CUT HERE
#ifndef call_from_test
signed main(){
  return 0;
}
#endif


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

//BEGIN CUT HERE
template<typename ...Ts>
decltype(auto) zip(vector<Ts>... args){
  vector<decltype(make_tuple(args[0]...))> res;
  int n=min({args.size()...});
  res.reserve(n);
  for(int i=0;i<n;i++) res.emplace_back(args[i]...);
  return res;
}
//END CUT HERE
#ifndef call_from_test
signed main(){
  vector<int> as({1,2,3});
  vector<string> bs({"a","b","c"});
  auto zs=zip(as,bs);
  for(auto [x,y]:zs) cout<<x<<" "<<y<<endl;
  return 0;
}
#endif

#ifndef call_from_test
#include<bits/stdc++.h>
using namespace std;
#endif
//BEGIN CUT HERE
enum Objective{
  MINIMIZE = +1,
  MAXIMIZE = -1,
};

template<typename T> struct Line {T k,m;};

template <typename T, Objective objective>
struct ConvexHullTrick : deque<Line<T>>{
  inline int sgn(T x){return x==0?0:(x<0?-1:1);}

  using D = long double;
  inline bool check(const Line<T> &a,const Line<T> &b,const Line<T> &c){
    if(b.m==a.m||c.m==b.m)
      return sgn(b.k-a.k)*sgn(c.m-b.m) >= sgn(c.k-b.k)*sgn(b.m-a.m);
    // return (b.k-a.k)*(c.m-b.m) >= (b.m-a.m)*(c.k-b.k);
    return
      D(b.k-a.k)*sgn(c.m-b.m)/D(abs(b.m-a.m)) >=
      D(c.k-b.k)*sgn(b.m-a.m)/D(abs(c.m-b.m));
  }

  using super = deque<Line<T>>;
  using super::empty,super::size,super::front,super::back;
  using super::emplace_front,super::emplace_back;
  using super::pop_front,super::pop_back;
  const Line<T> at(int i) const{return (*this)[i];}

  void add(T k_,T m_){
    Line<T> l({k_*objective,m_*objective});
    if(empty()){
      emplace_front(l);
      return;
    }
    if(front().k<=l.k){
      if(front().k==l.k){
        if(front().m<=l.m) return;
        pop_front();
      }
      while(size()>=2 and check(l,at(0),at(1))) pop_front();
      emplace_front(l);
    }else{
      assert(l.k<=back().k);
      if(back().k==l.k){
        if(back().m<=l.m) return;
        pop_back();
      }
      while(size()>=2 and check(at(size()-2),at(size()-1),l)) pop_back();
      emplace_back(l);
    }
  }

  inline T getY(const Line<T> &a,const T &x){return a.k*x+a.m;}

  T query(T x){
    assert(!empty());
    int l=-1,r=size()-1;
    while(l+1<r){
      int m=(l+r)>>1;
      if(getY(at(m),x)>=getY(at(m+1),x)) l=m;
      else r=m;
    }
    return getY(at(r),x)*objective;
  }

  T queryMonotoneInc(T x){
    assert(!empty());
    while(size()>=2 and getY(at(0),x)>=getY(at(1),x)) pop_front();
    return getY(front(),x)*objective;
  }

  T queryMonotoneDec(T x){
    assert(!empty());
    while(size()>=2 and getY(at(size()-1),x)>=getY(at(size()-2),x)) pop_back();
    return getY(back(),x)*objective;
  }
};
template<typename T>
using MinConvexHullTrick = ConvexHullTrick<T, Objective::MINIMIZE>;
template<typename T>
using MaxConvexHullTrick = ConvexHullTrick<T, Objective::MAXIMIZE>;
//END CUT HERE
#ifndef call_from_test
signed main(){
  return 0;
}
#endif

#undef call_from_test

signed main(){
  cin.tie(0);
  ios::sync_with_stdio(0);
  using ll = long long;

  int n,x;
  cin>>n>>x;
  vector<ll> ts(n),ps(n),fs(n);
  for(int i=0;i<n;i++) cin>>ts[i]>>ps[i]>>fs[i];

  auto vt=zip(fs,ps,ts);
  sort(vt.begin(),vt.end());
  for(int i=0;i<n;i++) tie(fs[i],ps[i],ts[i])=vt[i];

  vector<MaxConvexHullTrick<ll>> vh(x+1);

  ll ans=0;
  for(int i=0;i<n;i++){
    for(int j=x;j>ts[i];j--){
      if(vh[j-ts[i]].empty()) continue;
      ll val=vh[j-ts[i]].query(fs[i])+ps[i]-fs[i]*fs[i];
      vh[j].add(2*fs[i],val-fs[i]*fs[i]);
      chmax(ans,val);
    }
    vh[ts[i]].add(2*fs[i],ps[i]-fs[i]*fs[i]);
    chmax(ans,ps[i]);
  }

  cout<<ans<<endl;
  return 0;
}
accuracy: 1
time_ms: 440
memory_kb: 7880
final_rank: 11

code_snippet: // verification-helper: PROBLEM http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2725

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

#define call_from_test

#ifndef call_from_test
#include <bits/stdc++.h>
using namespace std;
#endif
//BEGIN CUT HERE
template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}
//END CUT HERE
#ifndef call_from_test
signed main(){
  return 0;
}
#endif


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

//BEGIN CUT HERE
template<typename ...Ts>
decltype(auto) zip(vector<Ts>... args){
  vector<decltype(make_tuple(args[0]...))> res;
  int n=min({args.size()...});
  res.reserve(n);
  for(int i=0;i<n;i++) res.emplace_back(args[i]...);
  return res;
}
//END CUT HERE
#ifndef call_from_test
signed main(){
  vector<int> as({1,2,3});
  vector<string> bs({"a","b","c"});
  auto zs=zip(as,bs);
  for(auto [x,y]:zs) cout<<x<<" "<<y<<endl;
  return 0;
}
#endif

#ifndef call_from_test
#include<bits/stdc++.h>
using namespace std;
#endif
//BEGIN CUT HERE
enum Objective{
  MINIMIZE = +1,
  MAXIMIZE = -1,
};

template <typename T, Objective objective>
struct ConvexHullTrick : deque<pair<T, T>>{
  #define F first
  #define S second
  using P = pair<T, T>;

  inline int sgn(T x){return x==0?0:(x<0?-1:1);}

  using D = long double;
  inline bool check(const P &a,const P &b,const P &c){
    if(b.S==a.S||c.S==b.S)
      return sgn(b.F-a.F)*sgn(c.S-b.S) >= sgn(c.F-b.F)*sgn(b.S-a.S);
    // return (b.F-a.F)*(c.S-b.S) >= (b.S-a.S)*(c.F-b.F);
    return
      D(b.F-a.F)*sgn(c.S-b.S)/D(abs(b.S-a.S)) >=
      D(c.F-b.F)*sgn(b.S-a.S)/D(abs(c.S-b.S));
  }

  using super = deque<P>;
  using super::empty,super::size,super::front,super::back;
  using super::emplace_front,super::emplace_back;
  using super::pop_front,super::pop_back;
  void add(T m,T b){
    //P line(m*objective,b*objective);
    P line(m,b);
    if(empty()){
      emplace_front(line);
      return;
    }
    if(front().F<=m){
      if(front().F==m){
        if(front().S<=b) return;
        pop_front();
      }
      while(size()>=2 and check(line,(*this)[0],(*this)[1]))
        pop_front();
      emplace_front(line);
    }else{
      assert(m<=back().F);
      if(back().F==m){
        if(back().S<=b) return;
        pop_back();
      }
      while(size()>=2 and check((*this)[size()-2],(*this)[size()-1],line))
        pop_back();
      emplace_back(line);
    }
  }

  inline T getY(const P &a,const T &x){return a.F*x+a.S;}

  T query(T x){
    assert(!empty());
    int l=-1,r=size()-1;
    while(l+1<r){
      int m=(l+r)>>1;
      if(getY((*this)[m],x)>=getY((*this)[m+1],x)) l=m;
      else r=m;
    }
    return getY((*this)[r],x)*objective;
  }

  T queryMonotoneInc(T x){
    assert(!empty());
    while(size()>=2 and getY((*this)[0],x)>=getY((*this)[1],x))
      pop_front();
    return getY(front(),x)*objective;
  }

  T queryMonotoneDec(T x){
    assert(!empty());
    while(size()>=2 and getY((*this)[size()-1],x)>=getY((*this)[size()-2],x))
      pop_back();
    return getY(back(),x)*objective;
  }
  #undef F
  #undef S
};
template<typename T>
using MinConvexHullTrick = ConvexHullTrick<T, Objective::MINIMIZE>;
template<typename T>
using MaxConvexHullTrick = ConvexHullTrick<T, Objective::MAXIMIZE>;
//END CUT HERE
#ifndef call_from_test
signed main(){
  return 0;
}
#endif

#undef call_from_test

signed main(){
  cin.tie(0);
  ios::sync_with_stdio(0);
  using ll = long long;

  int n,x;
  cin>>n>>x;
  vector<ll> ts(n),ps(n),fs(n);
  for(int i=0;i<n;i++) cin>>ts[i]>>ps[i]>>fs[i];

  auto vt=zip(fs,ps,ts);
  sort(vt.begin(),vt.end());
  for(int i=0;i<n;i++) tie(fs[i],ps[i],ts[i])=vt[i];

  vector<MaxConvexHullTrick<ll>> vh(x+1);

  ll ans=0;
  for(int i=0;i<n;i++){
    for(int j=x;j>ts[i];j--){
      if(vh[j-ts[i]].empty()) continue;
      ll val=vh[j-ts[i]].queryMonotoneInc(fs[i])+ps[i]-fs[i]*fs[i];
      vh[j].add(-2*fs[i],-(val-fs[i]*fs[i]));
      chmax(ans,val);
    }
    vh[ts[i]].add(-2*fs[i],-(ps[i]-fs[i]*fs[i]));
    chmax(ans,ps[i]);
  }

  cout<<ans<<endl;
  return 0;
}
accuracy: 1
time_ms: 210
memory_kb: 6672
final_rank: 6

code_snippet: // verification-helper: PROBLEM http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2725

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

#define call_from_test

#ifndef call_from_test
#include <bits/stdc++.h>
using namespace std;
#endif
//BEGIN CUT HERE
template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}
//END CUT HERE
#ifndef call_from_test
signed main(){
  return 0;
}
#endif


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

//BEGIN CUT HERE
template<typename ...Ts>
decltype(auto) zip(vector<Ts>... args){
  vector<decltype(make_tuple(args[0]...))> res;
  int n=min({args.size()...});
  res.reserve(n);
  for(int i=0;i<n;i++) res.emplace_back(args[i]...);
  return res;
}
//END CUT HERE
#ifndef call_from_test
signed main(){
  vector<int> as({1,2,3});
  vector<string> bs({"a","b","c"});
  auto zs=zip(as,bs);
  for(auto [x,y]:zs) cout<<x<<" "<<y<<endl;
  return 0;
}
#endif

#ifndef call_from_test
#include<bits/stdc++.h>
using namespace std;
#endif
//BEGIN CUT HERE
enum Objective{
  MINIMIZE = +1,
  MAXIMIZE = -1,
};

template <typename T, Objective objective>
struct ConvexHullTrick : deque<pair<T, T>>{
  #define F first
  #define S second
  using P = pair<T, T>;

  inline int sgn(T x){return x==0?0:(x<0?-1:1);}

  using D = long double;
  inline bool check(const P &a,const P &b,const P &c){
    if(b.S==a.S||c.S==b.S)
      return sgn(b.F-a.F)*sgn(c.S-b.S) >= sgn(c.F-b.F)*sgn(b.S-a.S);
    // return (b.F-a.F)*(c.S-b.S) >= (b.S-a.S)*(c.F-b.F);
    return
      D(b.F-a.F)*sgn(c.S-b.S)/D(abs(b.S-a.S)) >=
      D(c.F-b.F)*sgn(b.S-a.S)/D(abs(c.S-b.S));
  }

  using super = deque<P>;
  using super::empty,super::size,super::front,super::back;
  using super::emplace_front,super::emplace_back;
  using super::pop_front,super::pop_back;
  void add(T m,T b){
    P line(m*objective,b*objective);
    if(empty()){
      emplace_front(line);
      return;
    }
    if(front().F<=m){
      if(front().F==m){
        if(front().S<=b) return;
        pop_front();
      }
      while(size()>=2 and check(line,(*this)[0],(*this)[1]))
        pop_front();
      emplace_front(line);
    }else{
      assert(m<=back().F);
      if(back().F==m){
        if(back().S<=b) return;
        pop_back();
      }
      while(size()>=2 and check((*this)[size()-2],(*this)[size()-1],line))
        pop_back();
      emplace_back(line);
    }
  }

  inline T getY(const P &a,const T &x){return a.F*x+a.S;}

  T query(T x){
    assert(!empty());
    int l=-1,r=size()-1;
    while(l+1<r){
      int m=(l+r)>>1;
      if(getY((*this)[m],x)>=getY((*this)[m+1],x)) l=m;
      else r=m;
    }
    return getY((*this)[r],x)*objective;
  }

  T queryMonotoneInc(T x){
    assert(!empty());
    while(size()>=2 and getY((*this)[0],x)>=getY((*this)[1],x))
      pop_front();
    return getY(front(),x)*objective;
  }

  T queryMonotoneDec(T x){
    assert(!empty());
    while(size()>=2 and getY((*this)[size()-1],x)>=getY((*this)[size()-2],x))
      pop_back();
    return getY(back(),x)*objective;
  }
  #undef F
  #undef S
};
template<typename T>
using MinConvexHullTrick = ConvexHullTrick<T, Objective::MINIMIZE>;
template<typename T>
using MaxConvexHullTrick = ConvexHullTrick<T, Objective::MAXIMIZE>;
//END CUT HERE
#ifndef call_from_test
signed main(){
  return 0;
}
#endif

#undef call_from_test

signed main(){
  cin.tie(0);
  ios::sync_with_stdio(0);
  using ll = long long;

  int n,x;
  cin>>n>>x;
  vector<ll> ts(n),ps(n),fs(n);
  for(int i=0;i<n;i++) cin>>ts[i]>>ps[i]>>fs[i];

  auto vt=zip(fs,ps,ts);
  sort(vt.begin(),vt.end());
  for(int i=0;i<n;i++) tie(fs[i],ps[i],ts[i])=vt[i];

  vector<MinConvexHullTrick<ll>> vh(x+1);

  ll ans=0;
  for(int i=0;i<n;i++){
    for(int j=x;j>ts[i];j--){
      if(vh[j-ts[i]].empty()) continue;
      ll val=(-vh[j-ts[i]].queryMonotoneInc(fs[i]))+ps[i]-fs[i]*fs[i];
      vh[j].add(-2*fs[i],-(val-fs[i]*fs[i]));
      chmax(ans,val);
    }
    vh[ts[i]].add(-2*fs[i],-(ps[i]-fs[i]*fs[i]));
    chmax(ans,ps[i]);
  }

  cout<<ans<<endl;
  return 0;
}
accuracy: 1
time_ms: 220
memory_kb: 6560
final_rank: 8

code_snippet: // verification-helper: PROBLEM http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2725

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

#define call_from_test

#ifndef call_from_test
#include <bits/stdc++.h>
using namespace std;
#endif
//BEGIN CUT HERE
template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}
//END CUT HERE
#ifndef call_from_test
signed main(){
  return 0;
}
#endif


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

//BEGIN CUT HERE
template<typename ...Ts>
decltype(auto) zip(vector<Ts>... args){
  vector<decltype(make_tuple(args[0]...))> res;
  int n=min({args.size()...});
  res.reserve(n);
  for(int i=0;i<n;i++) res.emplace_back(args[i]...);
  return res;
}
//END CUT HERE
#ifndef call_from_test
signed main(){
  vector<int> as({1,2,3});
  vector<string> bs({"a","b","c"});
  auto zs=zip(as,bs);
  for(auto [x,y]:zs) cout<<x<<" "<<y<<endl;
  return 0;
}
#endif

#ifndef call_from_test
#include<bits/stdc++.h>
using namespace std;
#endif
//BEGIN CUT HERE
enum Objective{
  MINIMIZE = +1,
  MAXIMIZE = -1,
};

template <typename T, Objective objective>
struct ConvexHullTrick : deque<pair<T, T>>{
  #define F first
  #define S second
  using P = pair<T, T>;

  inline int sgn(T x){return x==0?0:(x<0?-1:1);}

  using D = long double;
  inline bool check(const P &a,const P &b,const P &c){
    if(b.S==a.S||c.S==b.S)
      return sgn(b.F-a.F)*sgn(c.S-b.S) >= sgn(c.F-b.F)*sgn(b.S-a.S);
    // return (b.F-a.F)*(c.S-b.S) >= (b.S-a.S)*(c.F-b.F);
    return
      D(b.F-a.F)*sgn(c.S-b.S)/D(abs(b.S-a.S)) >=
      D(c.F-b.F)*sgn(b.S-a.S)/D(abs(c.S-b.S));
  }

  using super = deque<P>;
  using super::empty,super::size,super::front,super::back;
  using super::emplace_front,super::emplace_back;
  using super::pop_front,super::pop_back;
  void add(T m,T b){
    P line(m*objective,b*objective);
    if(empty()){
      emplace_front(line);
      return;
    }
    if(front().F<=m){
      if(front().F==m){
        if(front().S<=b) return;
        pop_front();
      }
      while(size()>=2 and check(line,(*this)[0],(*this)[1]))
        pop_front();
      emplace_front(line);
    }else{
      assert(m<=back().F);
      if(back().F==m){
        if(back().S<=b) return;
        pop_back();
      }
      while(size()>=2 and check((*this)[size()-2],(*this)[size()-1],line))
        pop_back();
      emplace_back(line);
    }
  }

  inline T getY(const P &a,const T &x){return a.F*x+a.S;}

  T query(T x){
    assert(!empty());
    int l=-1,r=size()-1;
    while(l+1<r){
      int m=(l+r)>>1;
      if(getY((*this)[m],x)>=getY((*this)[m+1],x)) l=m;
      else r=m;
    }
    return getY((*this)[r],x)*objective;
  }

  T queryMonotoneInc(T x){
    assert(!empty());
    while(size()>=2 and getY((*this)[0],x)>=getY((*this)[1],x))
      pop_front();
    return getY(front(),x)*objective;
  }

  T queryMonotoneDec(T x){
    assert(!empty());
    while(size()>=2 and getY((*this)[size()-1],x)>=getY((*this)[size()-2],x))
      pop_back();
    return getY(back(),x)*objective;
  }
  #undef F
  #undef S
};
template<typename T>
using MinConvexHullTrick = ConvexHullTrick<T, Objective::MINIMIZE>;
template<typename T>
using MaxConvexHullTrick = ConvexHullTrick<T, Objective::MAXIMIZE>;
//END CUT HERE
#ifndef call_from_test
signed main(){
  return 0;
}
#endif

#undef call_from_test

signed main(){
  cin.tie(0);
  ios::sync_with_stdio(0);
  using ll = long long;

  int n,x;
  cin>>n>>x;
  vector<ll> ts(n),ps(n),fs(n);
  for(int i=0;i<n;i++) cin>>ts[i]>>ps[i]>>fs[i];

  auto vt=zip(fs,ps,ts);
  sort(vt.begin(),vt.end());
  for(int i=0;i<n;i++) tie(fs[i],ps[i],ts[i])=vt[i];

  vector<MinConvexHullTrick<ll>> vh(x+1);

  ll ans=0;
  for(int i=0;i<n;i++){
    for(int j=x;j>ts[i];j--){
      if(vh[j-ts[i]].empty()) continue;
      ll val=(-vh[j-ts[i]].query(fs[i]))+ps[i]-fs[i]*fs[i];
      vh[j].add(-2*fs[i],-(val-fs[i]*fs[i]));
      chmax(ans,val);
    }
    vh[ts[i]].add(-2*fs[i],-(ps[i]-fs[i]*fs[i]));
    chmax(ans,ps[i]);
  }

  cout<<ans<<endl;
  return 0;
}
accuracy: 1
time_ms: 450
memory_kb: 7840
final_rank: 12

code_snippet: #line 1 "test/aoj/2725.test.cpp"
// verification-helper: PROBLEM http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2725

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

//BEGIN CUT HERE
template <typename T, bool isMin>
struct ConvexHullTrick {
  #define F first
  #define S second
  using P = pair<T, T>;
  deque<P> H;
  bool empty()const{return H.empty();}
  void clear(){H.clear();}

  inline int sgn(T x){return x==0?0:(x<0?-1:1);}

  using D = long double;
  inline bool check(const P &a,const P &b,const P &c){
    if(b.S==a.S||c.S==b.S)
      return sgn(b.F-a.F)*sgn(c.S-b.S) >= sgn(c.F-b.F)*sgn(b.S-a.S);

    //return (b.F-a.F)*(c.S-b.S) >= (b.S-a.S)*(c.F-b.F);
    return
      D(b.F-a.F)*sgn(c.S-b.S)/D(abs(b.S-a.S)) >=
      D(c.F-b.F)*sgn(b.S-a.S)/D(abs(c.S-b.S));
  }

  void addLine(T m,T b){
    if(!isMin) m*=-1,b*=-1;
    P line(m,b);
    if(empty()){
      H.emplace_front(line);
      return;
    }
    if(H.front().F<=m){
      if(H.front().F==m){
        if(H.front().S<=b) return;
        H.pop_front();
      }
      while(H.size()>=2&&
            check(line,H.front(),H[1])) H.pop_front();
      H.emplace_front(line);
    }else{
      assert(m<=H.back().F);
      if(H.back().F==m){
        if(H.back().S<=b) return;
        H.pop_back();
      }
      while(H.size()>=2&&
            check(H[H.size()-2],H.back(),line)) H.pop_back();
      H.emplace_back(line);
    }
  }

  inline T getY(const P &a,const T &x){
    return a.F*x+a.S;
  }

  T query(T x){
    assert(!empty());
    int l=-1,r=H.size()-1;
    while(l+1<r){
      int m=(l+r)>>1;
      if(getY(H[m],x)>=getY(H[m+1],x)) l=m;
      else r=m;
    }
    if(isMin) return getY(H[r],x);
    return -getY(H[r],x);
  }

  T queryMonotoneInc(T x){
    assert(!empty());
    while(H.size()>=2&&
          getY(H.front(),x)>=getY(H[1],x)) H.pop_front();
    if(isMin) return getY(H.front(),x);
    return -getY(H.front(),x);
  }

  T queryMonotoneDec(T x){
    assert(!empty());
    while(H.size()>=2&&
          getY(H.back(),x)>=getY(H[H.size()-2],x)) H.pop_back();
    if(isMin) return getY(H.back(),x);
    return -getY(H.back(),x);
  }
  #undef F
  #undef S
};
//END CUT HERE

signed main(){
  cin.tie(0);
  ios::sync_with_stdio(0);

  using ll = long long;

  int n,x;
  cin>>n>>x;
  vector<ll> ts(n),ps(n),fs(n);
  for(int i=0;i<n;i++) cin>>ts[i]>>ps[i]>>fs[i];

  using T = tuple<ll, ll, ll>;
  vector<T> vt(n);
  for(int i=0;i<n;i++) vt[i]=T(fs[i],ps[i],ts[i]);
  sort(vt.begin(),vt.end());
  for(int i=0;i<n;i++) tie(fs[i],ps[i],ts[i])=vt[i];

  vector<ConvexHullTrick<ll, false> > vh(x+1);

  ll ans=0;
  for(int i=0;i<n;i++){
    for(int j=x;j>ts[i];j--){
      if(vh[j-ts[i]].empty()) continue;
      ll val=vh[j-ts[i]].queryMonotoneInc(fs[i])+ps[i]-fs[i]*fs[i];
      vh[j].addLine(2*fs[i],val-fs[i]*fs[i]);
      ans=max(ans,val);
    }
    vh[ts[i]].addLine(2*fs[i],ps[i]-fs[i]*fs[i]);
    ans=max(ans,ps[i]);
  }

  cout<<ans<<endl;
  return 0;
}
accuracy: 1
time_ms: 210
memory_kb: 6784
final_rank: 7