Submission #1156792

#TimeUsernameProblemLanguageResultExecution timeMemory
1156792Doncho_BonbonchoSalesman (IOI09_salesman)C++20
60 / 100
397 ms49176 KiB
#include <algorithm>
#include <bits/stdc++.h>
#include <iostream>
#include <random>
#include <utility>
#include <variant>
#include <vector>
using namespace std;

#ifndef LOCAL
#define cerr if(false) cerr
#endif

#define out( x ) #x << " = " << x << "  "
#define endl "\n"

template<class T, class T2>
inline bool chkmax(T &x, const T2 &y) { return x < y ? x = y, 1 : 0; }
template<class T, class T2>
inline bool chkmin(T &x, const T2 &y) { return x > y ? x = y, 1 : 0; }

typedef long long ll;
#define int ll
const ll mod = 1e9 + 7;
const ll inf = 1e17;
const int MAX_N = 5e5 + 42;

const ll neutr = -inf;

struct SegmentTree {
	std::vector<ll> tree;

	void build(){
		tree.assign(4 * MAX_N, neutr);
	}

	void set(int ind, ll val, int x = 1, int lx = 0, int rx = MAX_N) {
		if(lx == rx){
			chkmax(tree[x], val);
			return;
		}
		int m = (lx + rx) >> 1;
		if(ind <= m) 
			set(ind, val, 2*x, lx, m);
		else 
			set(ind, val, 2*x + 1, m+1, rx);

		tree[x] = std::max(tree[2*x], tree[2*x + 1]);
	}

	ll query(int l, int r, int x = 1, int lx = 0, int rx = MAX_N) {
		if(l > rx || lx > r) return neutr;
		if(l <= lx && rx <= r) return tree[x];

		int m = (lx + rx) >> 1;
		ll left = query(l, r, 2*x, lx, m);
		ll right = query(l, r, 2*x + 1, m+1, rx);

		return std::max(left, right);
	}
};

SegmentTree segUp;
SegmentTree segDown;

std::vector< std::pair< int, std::pair< int, int > > > v;

signed main(){
#ifndef LOCAL
	std::ios_base::sync_with_stdio(false); 
	std::cin.tie(NULL); 
	std::cout.tie(NULL);
#endif

	int n, U, D, L;
	std::cin >> n >> U >> D >> L;

	for(int i = 1; i <= n; i++){
		int t, l, c;
		std::cin >> t >> l >> c;
		v.push_back({t, {l, c}});
	}

	v.push_back({ -1, { L, 0 } });
	v.push_back({ mod, { L, 0 } });

	std::sort(v.begin(), v.end());

	segUp.build();
	segDown.build();

	std::vector<ll> dp(MAX_N, neutr);
	dp[L] = 0;
	segUp.set(L, -L * U + dp[L]);
	segDown.set(L, L * D + dp[L]);

	for (int i = 1; i < (int)v.size(); ) {
		int day = v[i].first;
		int groupStart = i, groupEnd = i;
		while(groupEnd < (int)v.size() && v[groupEnd].first == day)
			groupEnd++;

		int cnt = groupEnd - groupStart;
		vector<int> pos(cnt);
		vector<ll> base(cnt, neutr);
		for (int j = 0; j < cnt; j++) {
			pos[j] = v[groupStart + j].second.first;
			ll cand1 = segUp.query(pos[j], MAX_N - 1) + pos[j] * U;
			ll cand2 = segDown.query(0, pos[j]) - pos[j] * D;
			base[j] = max(cand1, cand2);
		}

		vector<ll> bestVal = base;
		for (int j = 1; j < cnt; j++) {
			bestVal[j] = max(bestVal[j], bestVal[j-1] - D * (pos[j] - pos[j-1]));
		}
		for (int j = cnt - 2; j >= 0; j--) {
			bestVal[j] = max(bestVal[j], bestVal[j+1] - U * (pos[j+1] - pos[j]));
		}

		for (int j = 0; j < cnt; j++){
			int currPos = pos[j];
			ll new_dp = bestVal[j] + v[groupStart + j].second.second;
			chkmax(dp[currPos], new_dp);
			segUp.set(currPos, -currPos * U + dp[currPos]);
			segDown.set(currPos, currPos * D + dp[currPos]);
		}

		i = groupEnd;
	}

	std::cout << dp[L] << endl;
	return 0;
}

#Verdict Execution timeMemoryGrader output
Fetching results...