Problem:
A: Attack the Moles

ICPC で良い成績を収めるには修行が欠かせない．うさぎは ICPC で勝ちたいので，今日も修行をすることにした．

今日の修行は，もぐらたたきを何回も行って，反射神経と記憶力を高めようというものである．出てくるもぐらを次々に叩き，出来るだけ多くのポイントを獲得したい．

もぐらが出てくる可能性のある場所は直線状に並んでいて，基準点からの距離によって座標が定まっている．うさぎはしばらく修行を続けるうちに，もぐらの出現する場所と時間が常に一緒であることに気が付いた．うさぎは，その情報をすべて記録し，コンピュータで解析を行うことにした．

もぐらを叩くには，もぐらの出現位置に手を動かした後，もぐらの出てくるタイミングにぴったり合わせてもぐらを叩かなければならない．もぐらをうまく叩けると，そのもぐらに応じてポイントを得ることが出来る．もぐらを叩く動作は一瞬で行うことが出来るが，手を移動させる速さには限界がある．うさぎはもぐらを叩くにあたって左右両方の手を用いることができる．左手と右手は独立に動かすことが可能であるが，左手は常に右手より座標が小さい位置に存在しなければならない．このような条件下で，最大でどれだけのポイントが得られるかを調べたい．

Input

N V XLeft XRight
X1 T1 P1
...
XN TN PN

N は出てくるもぐらの数，V は手を移動させられる最大の速さ，XLeft, XRight はそれぞれ，左手，右手の初期位置の座標である．Xi, Ti, Pi はそれぞれ，i 番目のもぐらの，出現する位置の座標，ゲーム開始から出現までの時間，叩けた際に得られるポイントである．

1 ≤ N ≤ 3,000，1 ≤ V ≤ 10,000，1 ≤ XLeft < XRight ≤ 100,000，1 ≤ X1 ≤ X2 ≤ ... ≤ XN ≤ 100,000，1 ≤ Ti ≤ 100,000，1 ≤ Pi ≤ 100,000 を満たす．(Xi, Ti) として同一の組は複数回現れない．

Output

うさぎが得られる最大のポイントを 1 行に出力せよ．

Sample Input 1

3 10 150 250
100 20 123
201 10 67
202 10 45

Sample Output 1

190

Sample Input 2

1 7 20 90
55 5 73

Sample Output 2

73

Sample Input 3

10 2 1000 2000
400 300 1
600 200 1
700 800 1
700 500 1
900 600 1
1000 700 1
1300 900 1
1400 400 1
1500 1000 1
2000 100 1

Sample Output 3

10

Solution in C (judge verdict: Accepted)

// AOJ 2290 Attack the Moles
// 2018.3.14 bal4u

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define INF 0x01010101010101LL
#define MAX 6005
typedef struct { int to, rev; int cap, cost; } EDGE;
EDGE *edge[MAX]; int hi[MAX], lim[MAX];
int V;				// 頂点数
char used[MAX];
int prevv[MAX], preve[MAX];
long long h[MAX], dist[MAX];

void check_lim(int a)
{
	if (hi[a] < lim[a]) return;
	if (lim[a] == 0) {
		lim[a] = 32, hi[a] = 0;
		edge[a] = malloc(sizeof(EDGE) *lim[a]);
	} else if (hi[a] == lim[a]) {
		int k = lim[a];
		if (k > 512) k = 512;
		lim[a] += k;
		edge[a] = realloc(edge[a], sizeof(EDGE) *lim[a]);
	}
}

void add_edge(int from, int to, int cap, int cost)
{
	int f, t;
	EDGE *e;

	check_lim(from), check_lim(to);
	f = hi[from]++, t = hi[to]++;
	e = &edge[from][f], e->to = to, e->cap = cap, e->cost = cost, e->rev = t; 
	e = &edge[to][t], e->to = from, e->cap = 0, e->cost = -cost, e->rev = f;
}

int minCostFlow(int S, int T, int F)
{
	int i, u, v, d, ret;
	long long t;
	EDGE *e;

	ret = 0;
	while (F > 0) {
		memset(dist, INF, V <<3), dist[S] = 0;
		memset(used, 0, V);
		while (1) {
			v = -1;
			for (u = 0; u < V; u++) if (!used[u] && (v < 0 || dist[v] > dist[u])) v = u;
			if (v < 0) break;
			used[v] = 1;
			for (i = 0; i < hi[v]; i++) {
				e = &edge[v][i]; 
				if (e->cap == 0) continue;
				t = dist[v] + e->cost + h[v] - h[e->to];
				if (dist[e->to] > t) dist[e->to] = t, prevv[e->to] = v, preve[e->to] = i;
			}
		}
		if (dist[T] == INF) return -1;
		for (v = 0; v < V; v++) h[v] += dist[v];

		d = F;
		for (v = T; v != S; v = prevv[v]) {
			e = &edge[prevv[v]][preve[v]];
			if (d > e->cap) d = e->cap;
		}
		F -= d;

		ret += d * h[T];
		for (v = T; v != S; v = prevv[v]) {
			e = &edge[prevv[v]][preve[v]];
			e->cap -= d;
			edge[v][e->rev].cap += d;
		}
	}
	return ret;
}

//#define getchar_unlocked()  getchar()
int in()
{
	int n = 0, c = getchar_unlocked();
	do n = 10*n + (c & 0xf), c = getchar_unlocked(); while (c >= '0');
	return n;
}

int  Q[MAX+5], top, end;
int  count[MAX];
void topologicalSort(int source)
{
	int i, j;
	EDGE *e;

	top = end = 0;
	for (i = 0; i < V; i++) for (j = 0; j < hi[i]; j++) if (edge[i][j].cap) count[edge[i][j].to]++;
	memset(h, INF, V << 3);
	for (i = 0; i < V; i++) if (!count[i]) { Q[end++] = i; if (i == source) h[i] = 0; }

	while (top < end) {
		i = Q[top++];
		for (j = 0; j < hi[i]; j++) {
			e = &edge[i][j];
			if (e->cap) {
				if (h[e->to] > h[i] + e->cost) h[e->to] = h[i] + e->cost;
				if (--count[e->to] == 0) Q[end++] = e->to;
			}
		}
	}
}

#define ABS(a)     ((a)>=0?(a):-(a))
typedef struct { int t, x, p; } TBL;
TBL tbl[3003];

int cmp(TBL *a, TBL *b) { return a->t - b->t; }

int main()
{
	int n, v, xl, xr, i, j;
	int source, sink, a, b;

	n = in(), v = in(), xl = in(), xr = in();
	for (i = 0; i < n; i++) tbl[i].x = in(), tbl[i].t = in(), tbl[i].p = in();
	qsort(tbl, n, sizeof(TBL), cmp);

	a = 2*n, b = a+1, source = b+1, sink = source+1, V = sink+1;

	add_edge(source, sink, 2, 0);
	add_edge(source, a, 1, 0), add_edge(source, b, 1, 0);
	for (i = 0; i < n; i++) {
		if (ABS(tbl[i].x - xl) <= tbl[i].t * v) add_edge(a, i<<1, 1, 0);
		if (ABS(tbl[i].x - xr) <= tbl[i].t * v) add_edge(b, i<<1, 1, 0);
		add_edge((i<<1)+1, sink, 1, 0);
		add_edge(i<<1, (i<<1)+1, 1, -tbl[i].p);
		for (j = i+1; j < n; j++) {
			if ((tbl[j].t-tbl[i].t)*v >= ABS(tbl[i].x-tbl[j].x)) add_edge((i<<1)+1, j<<1, 1, 0);
		}
	}
	topologicalSort(source);
	printf("%d\n", -minCostFlow(source, sink, 2));
	return 0;
}