J. The Silk Road . . . with Robots!
Parts of the ancient silk road passed through southern Kazakhstan. You’ve been fantasizing about a modern silk road, which has its own special features. Along your fantasy road are robots as well as stores holding stashes of tenges (the national currency of...
Problem Statement
Formatted from the contest statement text, with sample tests broken out into copyable blocks.
Parts of the ancient silk road passed through southern Kazakhstan. You’ve been fantasizing about a modern silk road, which has its own special features. Along your fantasy road are robots as well as stores holding stashes of tenges (the national currency of Kazakhstan). If a robot moves to a location with a store, the robot collects all of that store’s tenges for you. The cost of moving a robot is 1 tenge for every meter moved. So the amount of profit from moving a robot to Generated by ChatGPT 4o
a store is the number of tenges held by the store minus the number of meters the robot has moved to reach the store. Consider this scenario, which stretches over several days. Initially, the road is empty, with no robots or stores. Every day, either a new robot or a new store is placed on an unoccupied location along the road. Immediately before that, each existing store on the road is resupplied with tenges so that its total amount is the same as it was when it was first placed on the road, and each robot is returned to its original starting location. For each day, you need to determine the maximum amount of profit that could be gained by moving robots to collect tenges from the stores. Note that no two robots start in the same location, but they may occupy the same location as they move. Each store can be emptied of its tenges only once during a single day.
Input
The first line contains an integer n (1 ≤ n ≤ 2 · 105 ), the number of days. This is followed by n lines, where the ith line starts with an integer ti , which is equal to 1 if a new robot is added on day i, or is equal to 2 if a new store is added that day. It is followed by an integer xi (0 ≤ xi ≤ 108 ), denoting the location of the new robot or the new store. If ti = 2, the line contains another integer ci (0 ≤ ci ≤ 108 ), denoting the number of tenges at the store. All the given locations are distinct.
Output
Output n integers, the maximum profit you can make after each day.
Sample Tests
6
1 20
2 15 15
2 40 50
1 50
2 80 20
2 70 30 0
10
35
50
50
60 Editorial
The solution write-up is rendered from the LaTeX source, with equations kept live through MathJax.
Key Observations
In an optimal solution, the sets of stores collected by different robots form disjoint segments on the line.
For one robot covering one segment, the robot starts somewhere inside that segment. Therefore one side of the robot is traversed once and the other side is traversed twice.
Sweep the line from left to right. For the cut between two consecutive coordinates, only five states are possible:
no active segment crosses the cut;
the cut lies to the left of the responsible robot, and that part is traversed once;
the cut lies to the left of the responsible robot, and that part is traversed twice;
the cut lies to the right of the responsible robot, and that part is traversed once;
the cut lies to the right of the responsible robot, and that part is traversed twice.
Every coordinate acts as a local transition on these five states:
a road interval between two consecutive coordinates only subtracts travel cost depending on whether the cut is crossed $0$, $1$, or $2$ times;
a store gives its coins to every state in which the current point is covered, and it may also start or end a segment;
a robot may be ignored, may be the robot of an already-open segment, or may start a new segment extending to the right.
These local transitions are max-plus matrices. Their composition is associative, so a segment tree supports online insertions.
Algorithm
Collect all coordinates from the input and sort them once for coordinate compression.
Use the five sweep states listed above. For each coordinate, store a $5 \times 5$ max-plus transition matrix.
Road matrix for distance $\Delta$:
state $0$ keeps value unchanged;
the once-covered states subtract $\Delta$;
the twice-covered states subtract $2\Delta$.
Robot matrix:
every state may ignore the robot and stay unchanged;
state $0$ may start a new segment to the right;
a left-side state may use this robot as the responsible robot and either stop here or continue to the right with the complementary multiplicity.
Store matrix with value $c$:
if the current point is covered, add $c$ and keep the state;
a right-side state may also end the current segment here, adding $c$;
state $0$ may ignore the store, or may start a new segment here and add $c$.
Build a segment tree over the compressed coordinates. A leaf stores the event matrix at that coordinate. When combining two neighboring intervals, insert the road matrix for the gap between them: \[ M_{[l,r]} = M_{[l,mid]} \cdot R(\Delta) \cdot M_{[mid+1,r]}. \]
Initially every leaf is the identity event matrix, meaning that coordinate has not appeared yet. After each day, update one leaf to the corresponding robot/store matrix and output the value of state $0 \to 0$ in the root matrix. enumerate
Correctness Proof
We prove that the algorithm returns the correct answer.
Lemma 1.
In an optimal solution, every point on the line is traversed by at most one robot.
Proof.
If two robots both traverse the same point, then their covered segments overlap. Since stores can be collected only once, splitting the overlap between the two robots does not decrease collected money and cannot increase total travel cost. Therefore an optimal solution can always be transformed into one whose robot segments are pairwise disjoint. □
Lemma 2.
For a sweep cut between consecutive coordinates, the five states listed above contain all information needed to optimize the prefix independently of the suffix.
Proof.
By Lemma 1 at most one robot segment crosses the cut. If none crosses, we are in state $0$. Otherwise the cut lies either to the left or to the right of the responsible robot, and this portion of the route is traversed either once or twice. No other information from the prefix affects how the suffix may be completed. Hence the five states form a sufficient DP interface. □
Lemma 3.
The robot, store, and road matrices exactly describe all valid transitions between sweep states.
Proof.
For a road interval, the cut-crossing multiplicity does not change, and the only effect is subtracting travel cost once or twice.
For a store, every active segment covering that point collects its value. Additionally, state $0$ may start a new segment there, while a right-side state may finish there.
For a robot, we may always ignore it. If a segment already started to the left, this robot may become its responsible robot: either the segment ends here, or it continues to the right and the multiplicities on the two sides must complement each other (one side once, the other side twice). Also, a new segment may start at the robot and extend to the right. These are exactly the possibilities encoded in the matrix. □
Theorem.
The algorithm outputs the correct answer for every valid input.
Proof.
By Lemma 2, the optimum over any interval is fully described by a max-plus transition matrix on the five sweep states. By Lemma 3, the local matrices are correct. Because matrix composition corresponds exactly to concatenating neighboring parts of the line, the segment tree root stores the transition matrix for the entire current instance.
We start with no active segment to the left of the whole line and must also end with no active segment to the right, so the answer is the root entry for state $0 \to 0$. Therefore the reported value is exactly the maximum obtainable profit. □
Complexity Analysis
Each matrix multiplication is on constant size $5 \times 5$, so it is $O(1)$. Each day performs one segment tree update, hence $O(\log n)$ time. The total memory usage is $O(n)$.
Implementation Notes
The segment tree is built on all coordinates seen in the input, with inactive coordinates represented by the identity event matrix.
Use a sufficiently small negative infinity value for impossible transitions in max-plus multiplication.
All profits fit in
long long.
Code
C++ solution used for this page.
#include <bits/stdc++.h>
using namespace std;
namespace {
static constexpr long long kNegInf = -(1LL << 60);
static constexpr int kStates = 5;
struct Matrix {
long long value[kStates][kStates];
Matrix() {
for (int i = 0; i < kStates; ++i) {
for (int j = 0; j < kStates; ++j) {
value[i][j] = kNegInf;
}
}
}
};
Matrix multiply(const Matrix& a, const Matrix& b) {
Matrix result;
for (int i = 0; i < kStates; ++i) {
for (int k = 0; k < kStates; ++k) {
if (a.value[i][k] == kNegInf) {
continue;
}
for (int j = 0; j < kStates; ++j) {
if (b.value[k][j] == kNegInf) {
continue;
}
result.value[i][j] = max(result.value[i][j],
a.value[i][k] + b.value[k][j]);
}
}
}
return result;
}
Matrix make_identity_event() {
Matrix matrix;
for (int i = 0; i < kStates; ++i) {
matrix.value[i][i] = 0;
}
return matrix;
}
Matrix make_road(const long long distance) {
Matrix matrix;
matrix.value[0][0] = 0;
matrix.value[1][1] = -distance;
matrix.value[2][2] = -2 * distance;
matrix.value[3][3] = -distance;
matrix.value[4][4] = -2 * distance;
return matrix;
}
Matrix make_robot() {
Matrix matrix = make_identity_event();
matrix.value[0][3] = 0;
matrix.value[1][0] = 0;
matrix.value[2][0] = 0;
matrix.value[1][4] = 0;
matrix.value[2][3] = 0;
return matrix;
}
Matrix make_shop(const long long coins) {
Matrix matrix;
matrix.value[0][0] = 0;
matrix.value[0][1] = coins;
matrix.value[0][2] = coins;
matrix.value[1][1] = coins;
matrix.value[2][2] = coins;
matrix.value[3][3] = coins;
matrix.value[4][4] = coins;
matrix.value[3][0] = coins;
matrix.value[4][0] = coins;
return matrix;
}
struct SegmentTree {
int size = 0;
vector<Matrix> tree;
vector<int> positions;
explicit SegmentTree(vector<int> coords)
: size(static_cast<int>(coords.size())),
tree(4 * max(1, size)),
positions(std::move(coords)) {
if (size > 0) {
build(1, 0, size - 1);
}
}
void build(const int node, const int left, const int right) {
if (left == right) {
tree[node] = make_identity_event();
return;
}
const int mid = (left + right) / 2;
build(node * 2, left, mid);
build(node * 2 + 1, mid + 1, right);
pull(node, left, right);
}
void pull(const int node, const int left, const int right) {
const int mid = (left + right) / 2;
Matrix merged = multiply(tree[node * 2],
make_road(positions[mid + 1] - positions[mid]));
tree[node] = multiply(merged, tree[node * 2 + 1]);
}
void update(const int index, const Matrix& value) {
update(1, 0, size - 1, index, value);
}
void update(const int node,
const int left,
const int right,
const int index,
const Matrix& value) {
if (left == right) {
tree[node] = value;
return;
}
const int mid = (left + right) / 2;
if (index <= mid) {
update(node * 2, left, mid, index, value);
} else {
update(node * 2 + 1, mid + 1, right, index, value);
}
pull(node, left, right);
}
long long answer() const {
return tree[1].value[0][0];
}
};
void solve() {
int days;
cin >> days;
struct Query {
int type = 0;
int x = 0;
int c = 0;
};
vector<Query> queries(days);
vector<int> coords;
coords.reserve(days);
for (int i = 0; i < days; ++i) {
cin >> queries[i].type >> queries[i].x;
if (queries[i].type == 2) {
cin >> queries[i].c;
}
coords.push_back(queries[i].x);
}
sort(coords.begin(), coords.end());
coords.erase(unique(coords.begin(), coords.end()), coords.end());
SegmentTree seg(coords);
for (const Query& query : queries) {
const int index = static_cast<int>(
lower_bound(coords.begin(), coords.end(), query.x) - coords.begin());
if (query.type == 1) {
seg.update(index, make_robot());
} else {
seg.update(index, make_shop(query.c));
}
cout << seg.answer() << '\n';
}
}
} // namespace
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
solve();
return 0;
}
Source Files and Assets
Raw files are still available here when you want the original TeX, C++, or statement assets.
Show raw files
competitive_programming/icpc/2024/J-the-silk-road-with-robots/solution.texC++ implementationcompetitive_programming/icpc/2024/J-the-silk-road-with-robots/solution.cppStatement textcompetitive_programming/icpc/2024/J-the-silk-road-with-robots/statement.txtStatement PDFcompetitive_programming/icpc/2024/J-the-silk-road-with-robots/statement.pdfMetadatacompetitive_programming/icpc/2024/J-the-silk-road-with-robots/meta.jsonYear packetcompetitive_programming/icpc/2024/contest_problems.pdf