This submission is migrated from previous version of oj.uz, which used different machine for grading. This submission may have different result if resubmitted.
#include <bits/stdc++.h>
using namespace std;
class TreatmentProject {
private:
template<typename T> using min_queue = priority_queue<T, vector<T>, greater<T>>;
struct Project {
int T, L, R, C;
Project() {}
Project(int T, int L, int R, int C) : T(T), L(L), R(R), C(C) {}
};
int N_, M_;
vector<Project> project_;
long long NaiveDijkstraDP() { // O(M^2) Dijsktra-DP solution (naive)
int N = N_, M = M_;
vector<Project> project = project_;
assert(M <= 5000);
for (int i = 0; i < M; i++) {
project[i].R++;
} // project[i] cures [L[i], R[i])
vector<long long> dp(M, 1e18);
vector<bool> vis(M, false);
int current = -1;
for (int i = 0; i < M; i++) {
if (project[i].R > N) {
dp[i] = project[i].C;
if (current == -1 || dp[current] > dp[i]) {
current = i;
}
}
}
while (current != -1) { // Dijkstra's Algorithm
vis[current] = true;
for (int now = 0; now < M; now++) {
if (vis[now]) continue;
bool CanTransition = false;
if (project[now].T >= project[current].T) {
CanTransition = project[now].R >= project[current].L + (project[now].T - project[current].T);
} else {
CanTransition = project[now].R - (project[current].T - project[now].T) >= project[current].L;
}
if (CanTransition) {
dp[now] = min(dp[now], project[now].C + dp[current]);
}
}
int nxt = -1;
for (int now = 0; now < M; now++) {
if (vis[now]) continue;
if (nxt == -1 || dp[nxt] > dp[now]) {
nxt = now;
}
}
current = nxt;
}
long long res = 1e18;
for (int i = 0; i < M; i++) {
if (project[i].L == 1) {
res = min(res, dp[i]);
}
}
if (res == (long long) 1e18) { // no solution exists
res = -1;
}
return res;
}
class RangeTree { // O(log^2 M) per operation
private:
class DisjointSet {
private:
int BASE = 5;
vector<int> p;
int Find_(int x) {
return p[x] == x ? x : p[x] = Find_(p[x]);
}
bool Union_(int x, int y) { // p[x] = y
x = Find_(x), y = Find_(y);
if (x != y) {
p[x] = y;
return true;
} else {
return false;
}
}
public:
DisjointSet() {}
void Init(int n) {
p.resize(n + BASE + BASE);
iota(begin(p), end(p), 0);
}
int Find(int x) {
return Find_(x + BASE) - BASE;
}
bool Union(int x, int y) {
return Union_(x + BASE, y + BASE);
}
};
int sz;
vector<vector<pair<int, int>>> tree; // sorted vector (time, index)
vector<DisjointSet> dsu;
int LowerBound(int n, pair<int, int> x) { // lower_bound on tree[n]
int lo = 0, hi = tree[n].size();
while (lo < hi) {
int mid = (lo + hi) / 2;
if (mid >= 0 && tree[n][mid] >= x) {
hi = mid;
} else {
lo = mid + 1;
}
}
return dsu[n].Find(hi);
}
bool VectorErase(int n, pair<int, int> x) {
int pos = LowerBound(n, x);
if (pos < tree[n].size() && tree[n][pos] == x) {
dsu[n].Union(pos, pos + 1);
return true;
} else {
return false;
}
}
vector<Project> project;
vector<pair<int, int>> base;
void Pull(int n) {
dsu[n].Init(tree[n * 2].size() + tree[n * 2 + 1].size());
tree[n].resize(tree[n * 2].size() + tree[n * 2 + 1].size());
merge(begin(tree[n * 2]), end(tree[n * 2]), begin(tree[n * 2 + 1]), end(tree[n * 2 + 1]), begin(tree[n]));
}
void Build(int n, int tl, int tr, const vector<pair<int, int>> &a) { // tree = (time, index)
if (tl == tr) {
dsu[n].Init(1);
tree[n].emplace_back(make_pair(project[a[tl].second].T, a[tl].second));
return;
}
int mid = (tl + tr) / 2;
Build(n * 2, tl, mid, a);
Build(n * 2 + 1, mid + 1, tr, a);
Pull(n);
}
void Erase(int n, int tl, int tr, const pair<int, int> &a) { // element a to be deleted from segment tree
if (!VectorErase(n, a)) return;
if (tl == tr) return;
int mid = (tl + tr) / 2;
Erase(n * 2, tl, mid, a);
Erase(n * 2 + 1, mid + 1, tr, a);
}
void Query(int n, int tl, int tr, int l, int r, int t1, int t2, vector<int> &res) {
if (tr < l || r < tl || tl > tr || l > r) return;
if (l <= tl && tr <= r) {
int pos = LowerBound(n, make_pair(t1, INT_MIN));
while (pos < tree[n].size()) {
if (tree[n][pos].first > t2) break;
assert(t1 <= tree[n][pos].first && tree[n][pos].first <= t2);
res.emplace_back(tree[n][pos].second);
pos = dsu[n].Find(pos + 1);
}
return;
}
int mid = (tl + tr) / 2;
Query(n * 2, tl, mid, l, r, t1, t2, res);
Query(n * 2 + 1, mid + 1, tr, l, r, t1, t2, res);
}
public:
RangeTree(int n, const vector<Project> &proj) {
sz = n;
project = proj;
tree.resize(4 * n);
dsu.resize(4 * n);
}
void Build(const vector<pair<int, int>> &a) {
base = a;
return Build(1, 0, sz - 1, a);
}
void Erase(int x) {
return Erase(1, 0, sz - 1, pair<int, int>(project[x].T, x));
}
void Query(int l, int r, int t1, int t2, vector<int> &res) { // get ids from segment [l, r] with time <= t, and place it into res
l = lower_bound(begin(base), end(base), make_pair(l, INT_MIN)) - begin(base);
r = upper_bound(begin(base), end(base), make_pair(r, INT_MAX)) - begin(base) - 1;
return Query(1, 0, sz - 1, l, r, t1, t2, res);
}
};
long long RangeTreeDijkstraDP() { // O(M log^2 M) Dijkstra-DP solution (optimized with RangeTree)
int N = N_, M = M_;
vector<Project> project = project_;
for (int i = 0; i < M; i++) {
project[i].R++;
}
RangeTree RMinusT(M, project), RPlusT(M, project);
{ // Initialize RMinusT (base sorted by R[i] - T[i])
vector<pair<Project, int>> a;
for (int i = 0; i < M; i++) {
a.emplace_back(project[i], i);
}
sort(begin(a), end(a), [&](const pair<Project, int> &a, const pair<Project, int> &b) {
return a.first.R - a.first.T < b.first.R - b.first.T;
});
vector<pair<int, int>> base; // (R - T, index)
for (auto &i : a) {
base.emplace_back(i.first.R - i.first.T, i.second);
}
RMinusT.Build(base);
}
{ // Initialize RPlusT (base sorted by R[i] + T[i])
vector<pair<Project, int>> a;
for (int i = 0; i < M; i++) {
a.emplace_back(project[i], i);
}
sort(begin(a), end(a), [&](const pair<Project, int> &a, const pair<Project, int> &b) {
return a.first.R + a.first.T < b.first.R + b.first.T;
});
vector<pair<int, int>> base; // (R + T, index)
for (auto &i : a) {
base.emplace_back(i.first.R + i.first.T, i.second);
}
RPlusT.Build(base);
}
min_queue<pair<long long, int>> pq;
vector<long long> dp(M, 1e18);
for (int i = 0; i < M; i++) {
if (project[i].R > N) {
dp[i] = project[i].C;
pq.emplace(dp[i], i);
RMinusT.Erase(i);
RPlusT.Erase(i);
}
}
while (!pq.empty()) {
int cur = pq.top().second;
pq.pop();
vector<int> candidates;
RMinusT.Query(project[cur].L - project[cur].T, INT_MAX, project[cur].T, INT_MAX, candidates);
RPlusT.Query(project[cur].L + project[cur].T, INT_MAX, 1, project[cur].T, candidates);
sort(begin(candidates), end(candidates));
candidates.resize(unique(begin(candidates), end(candidates)) - begin(candidates));
for (auto &i : candidates) {
dp[i] = project[i].C + dp[cur];
pq.emplace(dp[i], i);
RMinusT.Erase(i);
RPlusT.Erase(i);
}
}
long long res = 1e18;
for (int i = 0; i < M; i++) {
if (project[i].L == 1) {
res = min(res, dp[i]);
}
}
if (res == (long long) 1e18) {
res = -1;
}
return res;
}
class SegmentTree { // O(log M) per operation
private:
int sz;
vector<pair<int, int>> tree_max; // (time, index), sorted by R - T
vector<pair<int, int>> tree_min; // (time, index), sorted by R + T
vector<Project> project;
vector<pair<int, int>> base_max;
vector<pair<int, int>> base_min;
vector<int> reverse_max;
vector<int> reverse_min;
public:
SegmentTree(int n, const vector<Project> &p) {
sz = n;
project = p;
tree_max.assign(2 * sz, {-1, -1});
tree_min.assign(2 * sz, {INT_MAX, -1});
}
void BuildMax(const vector<pair<int, int>> &a) {
base_max = a;
reverse_max.resize(a.size());
for (int i = 0; i < a.size(); i++) {
tree_max[i + sz] = make_pair(project[a[i].second].T, a[i].second);
reverse_max[a[i].second] = i;
}
for (int i = sz - 1; i > 0; i--) {
tree_max[i] = max(tree_max[i * 2], tree_max[i * 2 + 1]);
}
}
void BuildMin(const vector<pair<int, int>> &a) {
base_min = a;
reverse_min.resize(a.size());
for (int i = 0; i < a.size(); i++) {
tree_min[i + sz] = make_pair(project[a[i].second].T, a[i].second);
reverse_min[a[i].second] = i;
}
for (int i = sz - 1; i > 0; i--) {
tree_min[i] = min(tree_min[i * 2], tree_min[i * 2 + 1]);
}
}
int QueryMax(int l, int r, int t) { // suffix t...inf
l = lower_bound(begin(base_max), end(base_max), make_pair(l, INT_MIN)) - begin(base_max);
r = upper_bound(begin(base_max), end(base_max), make_pair(r, INT_MAX)) - begin(base_max) - 1;
pair<int, int> res = {-1, -1};
for (l += sz, r += sz + 1; l < r; l /= 2, r /= 2) {
if (l & 1) res = max(res, tree_max[l++]);
if (r & 1) res = max(res, tree_max[--r]);
}
return res.first < t ? -1 : res.second;
}
int QueryMin(int l, int r, int t) { // prefix 1...t
l = lower_bound(begin(base_min), end(base_min), make_pair(l, INT_MIN)) - begin(base_min);
r = upper_bound(begin(base_min), end(base_min), make_pair(r, INT_MAX)) - begin(base_min) - 1;
pair<int, int> res = {INT_MAX, -1};
for (l += sz, r += sz + 1; l < r; l /= 2, r /= 2) {
if (l & 1) res = min(res, tree_min[l++]);
if (r & 1) res = min(res, tree_min[--r]);
}
return res.first > t ? -1 : res.second;
}
void EraseMax(int id) {
id = reverse_max[id];
tree_max[id += sz] = {-1, -1};
for (id /= 2; id > 0; id /= 2) {
tree_max[id] = max(tree_max[id * 2], tree_max[id * 2 + 1]);
}
}
void EraseMin(int id) {
id = reverse_min[id];
tree_min[id += sz] = {INT_MAX, -1};
for (id /= 2; id > 0; id /= 2) {
tree_min[id] = min(tree_min[id * 2], tree_min[id * 2 + 1]);
}
}
};
long long SegmentTreeDijkstraDP() { // O(M log M) Dijkstra-DP solution (optimized with SegmentTree)
int N = N_, M = M_;
vector<Project> project = project_;
for (int i = 0; i < M; i++) {
project[i].R++;
}
SegmentTree SegTree(M, project);
// RangeTree RMinusT(M, project), RPlusT(M, project); // O(log^2 M) per operation
{ // Initialize RMinusT (base sorted by R[i] - T[i])
vector<pair<Project, int>> a;
for (int i = 0; i < M; i++) {
a.emplace_back(project[i], i);
}
sort(begin(a), end(a), [&](const pair<Project, int> &a, const pair<Project, int> &b) {
return a.first.R - a.first.T < b.first.R - b.first.T;
});
vector<pair<int, int>> base; // (R - T, index)
for (auto &i : a) {
base.emplace_back(i.first.R - i.first.T, i.second);
}
SegTree.BuildMax(base);
}
{ // Initialize RPlusT (base sorted by R[i] + T[i])
vector<pair<Project, int>> a;
for (int i = 0; i < M; i++) {
a.emplace_back(project[i], i);
}
sort(begin(a), end(a), [&](const pair<Project, int> &a, const pair<Project, int> &b) {
return a.first.R + a.first.T < b.first.R + b.first.T;
});
vector<pair<int, int>> base; // (R + T, index)
for (auto &i : a) {
base.emplace_back(i.first.R + i.first.T, i.second);
}
SegTree.BuildMin(base);
}
min_queue<pair<long long, int>> pq;
vector<long long> dp(M, 1e18);
for (int i = 0; i < M; i++) {
if (project[i].R > N) {
dp[i] = project[i].C;
pq.emplace(dp[i], i);
SegTree.EraseMax(i);
SegTree.EraseMin(i);
}
}
while (!pq.empty()) {
int cur = pq.top().second;
pq.pop();
vector<int> candidates;
while (true) { // get ids which satisfies R - T constraints
int now = SegTree.QueryMax(project[cur].L - project[cur].T, INT_MAX, project[cur].T);
if (now == -1) break;
SegTree.EraseMax(now);
SegTree.EraseMin(now);
candidates.emplace_back(now);
}
while (true) { // get ids which satisfies R + T constraints
int now = SegTree.QueryMin(project[cur].L + project[cur].T, INT_MAX, project[cur].T);
if (now == -1) break;
SegTree.EraseMax(now);
SegTree.EraseMin(now);
candidates.emplace_back(now);
}
for (auto &i : candidates) {
dp[i] = project[i].C + dp[cur];
pq.emplace(dp[i], i);
}
}
long long res = 1e18;
for (int i = 0; i < M; i++) {
if (project[i].L == 1) {
res = min(res, dp[i]);
}
}
if (res == (long long) 1e18) {
res = -1;
}
return res;
}
public:
void Read() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> N_ >> M_;
for (int i = 0; i < M_; i++) {
int T, L, R, C;
cin >> T >> L >> R >> C;
project_.emplace_back(T, L, R, C);
}
}
long long Solve() {
return SegmentTreeDijkstraDP();
}
};
int main() {
TreatmentProject Solver;
Solver.Read();
cout << Solver.Solve() << "\n";
return 0;
}
Compilation message (stderr)
treatment.cpp: In member function 'bool TreatmentProject::RangeTree::VectorErase(int, std::pair<int, int>)':
treatment.cpp:155:15: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
if (pos < tree[n].size() && tree[n][pos] == x) {
~~~~^~~~~~~~~~~~~~~~
treatment.cpp: In member function 'void TreatmentProject::RangeTree::Query(int, int, int, int, int, int, int, std::vector<int>&)':
treatment.cpp:196:20: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
while (pos < tree[n].size()) {
~~~~^~~~~~~~~~~~~~~~
treatment.cpp: In member function 'void TreatmentProject::SegmentTree::BuildMax(const std::vector<std::pair<int, int> >&)':
treatment.cpp:354:25: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
for (int i = 0; i < a.size(); i++) {
~~^~~~~~~~~~
treatment.cpp: In member function 'void TreatmentProject::SegmentTree::BuildMin(const std::vector<std::pair<int, int> >&)':
treatment.cpp:366:25: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
for (int i = 0; i < a.size(); i++) {
~~^~~~~~~~~~
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |