// https://onlinejudge.u-aizu.ac.jp/challenges/search/categories/2290
// MLEです (頂点型をshortにして、容量型をcharにすると多分通ります)
#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>
#include <limits>
template <typename T>
constexpr T INF() { return std::numeric_limits<T>::max() / 16; }
#include <vector>
template <typename Cap, typename Cost, typename Ind = std::size_t>
struct CostFlow
{
    CostFlow(const Ind v) : V(v), edge(v) { edge.shrink_to_fit(); }
    void addEdge(const Ind from, const Ind to, const Cap cap, const Cost cost) { edge[from].push_back(Edge{to, (Ind)edge[to].size(), cap, cost, false}), edge[to].push_back(Edge{from, (Ind)(edge[from].size() - 1), 0, -cost, true}); }
    struct Edge
    {
        Ind to, rev;
        Cap cap;
        Cost cost;
        const bool isrev;
    };
    const Ind V;
    std::vector<std::vector<Edge>> edge;
};
template <typename T, template <typename, typename, typename, typename> class PotFunc, typename Cap, typename Cost, typename Ind>
std::pair<bool, T> PrimalDual(CostFlow<Cap, Cost, Ind>& cflow, const Ind s, const Ind t, Cap f)
{
    const Ind V = cflow.V;
    T ans = 0;
    std::vector<T> potential = PotFunc<T, Cap, Cost, Ind>()(cflow, s);
    std::vector<T> dist(V, INF<T>());
    using P = std::pair<T, Ind>;
    std::priority_queue<P, std::vector<P>, std::greater<P>> Q;
    std::vector<Ind> prev_v(V), prev_e(V);
    dist.shrink_to_fit(), prev_v.shrink_to_fit(), prev_e.shrink_to_fit();
    while (f > 0) {
        std::fill(dist.begin(), dist.end(), INF<T>());
        dist[s] = 0, Q.push({0, s});
        while (not Q.empty()) {
            const T cost = Q.top().first;
            const Ind v = Q.top().second;
            Q.pop();
            if (dist[v] < cost) { continue; }
            for (Ind i = 0; i < cflow.edge[v].size(); i++) {
                const auto& e = cflow.edge[v][i];
                const T pd = potential[v] - potential[e.to];
                if (e.cap == 0 or dist[e.to] <= dist[v] + e.cost + pd) { continue; }
                dist[e.to] = dist[v] + e.cost + pd, prev_v[e.to] = v, prev_e[e.to] = i;
                Q.push({dist[e.to], e.to});
            }
        }
        if (dist[t] == INF<T>()) { return {false, ans}; }
        for (Ind v = 0; v < V; v++) { potential[v] += dist[v]; }
        Cap d = f;
        for (Ind v = t; v != s; v = prev_v[v]) {
            const auto& e = cflow.edge[prev_v[v]][prev_e[v]];
            d = std::min(d, e.cap);
        }
        f -= d, ans += (T)d * potential[t];
        for (Ind v = t; v != s; v = prev_v[v]) {
            auto& e = cflow.edge[prev_v[v]][prev_e[v]];
            e.cap -= d, cflow.edge[v][e.rev].cap += d;
        }
    }
    return {true, ans};
}
#include <algorithm>
#include <vector>
struct Graph
{
    Graph(const std::size_t v) : V{v}, edge(v), rev_edge(v) {}
    void addEdge(const std::size_t from, const std::size_t to) { edge[from].push_back(to), rev_edge[to].push_back(from); }
    const std::size_t V;
    std::vector<std::vector<std::size_t>> edge, rev_edge;
};
std::pair<bool, std::vector<std::size_t>> TopSort(const Graph& g)
{
    std::vector<std::size_t> srt, used(g.V, 0);
    auto dfs = [&](auto&& self, const std::size_t s) -> bool {
        if (used[s] == 1) {
            return false;
        } else if (used[s] == 0) {
            used[s] = 1;
            for (const std::size_t to : g.edge[s]) {
                if (not self(self, to)) { return false; }
            }
            used[s] = 2, srt.push_back(s);
        }
        return true;
    };
    for (std::size_t i = 0; i < g.V; i++) {
        if (not dfs(dfs, i)) { return {false, srt}; }
    }
    std::reverse(srt.begin(), srt.end());
    return {true, srt};
}
template <typename T, typename Cap, typename Cost, typename Ind>
struct PotDAG
{
    std::vector<T> operator()(const CostFlow<Cap, Cost, Ind>& cflow, const Ind s) const
    {
        const Ind V = cflow.V;
        std::vector<Ind> ord(V);
        for (Ind i = 0; i < V; i++) { ord[i] = i; }
        std::vector<T> ans(V, INF<T>());
        ans.shrink_to_fit();
        for (Ind i = 0; i < V; i++) {
            if (ord[i] == s) { ans[s] = 0; }
            for (const auto& e : cflow.edge[ord[i]]) {
                if (e.cap == 0) { continue; }
                ans[e.to] = std::min(ans[e.to], ans[ord[i]] + e.cost);
            }
        }
        return ans;
    }
};
struct Point
{
    int X, T, P;
    bool operator<(const Point& p) const
    {
        return T < p.T;
    }
};

int main()
{
    short N;
    std::cin >> N;
    std::size_t V, L, R;
    std::cin >> V >> L >> R;
    std::vector<Point> point(N);
    point.shrink_to_fit();
    for (short i = 0; i < N; i++) { std::cin >> point[i].X >> point[i].T >> point[i].P; }
    std::sort(point.begin(), point.end());
    CostFlow<char, int, short> cflow(2 * N + 4);
    const short s = 0, t = 2 * N + 3, l = 1, r = 2;
    cflow.addEdge(s, l, 1, 0), cflow.addEdge(s, r, 1, 0);
    for (short i = 0; i < N; i++) {
        cflow.addEdge(2 * i + 3, 2 * i + 4, 1, 0), cflow.addEdge(2 * i + 4, t, 1, -point[i].P);
        if (std::abs(point[i].X - (int)L) <= V * point[i].T) { cflow.addEdge(l, 2 * i + 3, 1, 0); }
        if (std::abs(point[i].X - (int)R) <= V * point[i].T) { cflow.addEdge(r, 2 * i + 3, 1, 0); }
    }
    for (short i = 0; i < N; i++) {
        for (short j = i + 1; j < N; j++) {
            if (std::abs(point[i].X - point[j].X) <= V * (point[j].T - point[i].T)) { cflow.addEdge(2 * i + 4, 2 * j + 3, 1, -point[i].P); }
        }
    }
    point.clear(), point.shrink_to_fit();
    std::cout << -PrimalDual<int, PotDAG>(cflow, s, t, (char)2).second << std::endl;

    return 0;
}


Measured memory_bytes: 241684