#include <bits/stdc++.h>
using namespace std;
struct Point {
int x, y;
Point operator-(const Point p) const { return {x - p.x, y - p.y}; }
void operator+=(const Point p) {
x += p.x;
y += p.y;
}
bool operator<(const Point p) const { return x < p.x || (x == p.x && y < p.y); }
int dist(const Point p) const { return abs(p.x - x) + abs(p.y - y); }
};
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n;
Point dest;
while (cin >> dest.x >> dest.y >> n) {
vector<tuple<int, int, int, int>> events;
for (int i = 0; i < n; i++) {
int x1, y1, x2, y2;
cin >> x1 >> y1 >> x2 >> y2;
if (x1 > x2) swap(x1, x2);
if (y1 > y2) swap(y1, y2);
events.emplace_back(x1 - 1, 1, y1 - 1, y2 + 1);
events.emplace_back(x2 + 1, 0, y1 - 1, y2 + 1);
}
// TODO: This is weird. Make the ordering more explicit as to why it works that way.
const int DEST = -1;
events.emplace_back(dest.x, DEST, dest.y, dest.y);
sort(events.begin(), events.end());
map<int, Point> m;
map<Point, Point> prev_point;
// TODO: Find a better infinity value. Or try to get rid of it.
const int inf = 1e8;
m[0] = {0, 0};
// TODO: This data is weird lmao
m[-inf] = {-inf, -inf};
m[inf] = {-inf, inf};
map<Point, int> dist;
dist[{0, 0}] = 0;
const auto update = [&](const Point p) {
const auto it0 = m.lower_bound(p.y);
const auto it1 = it0->first == p.y ? it0 : prev(it0);
for (const auto it : {it0, it1}) {
const Point point = it->second;
// TODO: This looks like a Dijkstra implementation, but it's not, so make it
// adhoc (on purpose).
const int alt = dist[point] + p.dist(point);
if (!dist.count(p) || dist[p] > alt) {
prev_point[p] = point;
dist[p] = alt;
}
}
m[p.y] = p;
};
for (const auto& [x, type, y1, y2] : events) {
// TODO: This is kinda shit.
if (type == DEST) {
update({x, y1});
break;
} else {
update({x, y1});
update({x, y2});
}
while (true) {
const auto it = m.lower_bound(y1 + 1);
if (y2 <= it->first) break;
m.erase(it);
}
}
vector<Point> path{dest};
Point curr = dest;
// TODO: Maybe use do while??? More idiomatic.
while (curr.x != 0 || curr.y != 0) {
path.emplace_back(curr);
curr = prev_point[curr];
}
path.emplace_back(curr);
reverse(path.begin(), path.end());
vector<Point> deltas;
for (size_t i = 0; i < path.size() - 1; i++) {
const Point d = path[i + 1] - path[i];
if (d.x != 0 && d.y != 0) {
deltas.emplace_back(d.x, 0);
deltas.emplace_back(0, d.y);
} else {
deltas.emplace_back(d);
}
}
vector<Point> merged{deltas.front()};
for (size_t i = 1; i < deltas.size(); i++) {
const Point d = deltas[i];
if ((merged.back().y == 0 && d.y == 0) || (merged.back().x == 0 && d.x == 0)) {
merged.back() += d;
} else {
merged.emplace_back(d);
}
}
int total_len = 0;
for (const Point d : merged) {
total_len += d.x;
total_len += abs(d.y);
}
cout << total_len << endl;
cout << merged.size() << endl;
for (const Point d : merged) {
cout << d.x << ' ' << d.y << endl;
}
}
}
| # | Verdict | Execution time | Memory | Grader output |
|---|
| Fetching results... |