제출 #1334224

#제출 시각아이디문제언어결과실행 시간메모리
1334224LIAWalk (CEOI06_walk)C++17
98 / 100
133 ms34824 KiB
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define v vector
#define lp(i, s, e) for (ll i = s; i < e; ++i)
#define tpl tuple<ll, ll, ll, ll, ll, ll>

struct Seg {
  Seg *left = nullptr, *right = nullptr;
  int l, r, mid;
  int id = -1, lazy = -1;

  Seg(int l, int r) : l(l), r(r), mid((l + r) / 2) {}

  void ensure() {
    if (l == r)
      return;
    if (left == nullptr) {
      left = new Seg(l, mid);
      right = new Seg(mid + 1, r);
    }
  }

  void push() {
    if (lazy == -1)
      return;
    id = lazy;
    if (l != r) {
      ensure();
      left->lazy = lazy;
      right->lazy = lazy;
    }
    lazy = -1;
  }

  int q(int pos) {
    push();
    if (l == r)
      return id;
    ensure();
    if (pos <= mid)
      return left->q(pos);
    return right->q(pos);
  }

  void update(int a, int b, int V) {
    push();
    if (l > b || r < a)
      return;
    if (l >= a && r <= b) {
      lazy = V;
      push();
      return;
    }
    ensure();
    left->update(a, b, V);
    right->update(a, b, V);
  }
};

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);

  ll dest_x, dest_y;
  cin >> dest_x >> dest_y;
  ll n;
  cin >> n;
  vector<tpl> vec;
  v<ll> y_val;

  y_val.push_back(dest_y);
  y_val.push_back(0);

  v<ll> B_bottom(1), B_top(1), B_left(1), B_right(1);
  ll cnt = 0;

  lp(i, 0, n) {
    ll a, b, c, d;
    cin >> a >> b >> c >> d;

    ll lx = min(a, c), rx = max(a, c);
    ll ly = min(b, d), ry = max(b, d);

    if (lx >= dest_x)
      continue;

    rx = min(rx, dest_x);

    ++cnt;
    B_left.push_back(lx);
    B_right.push_back(rx);
    B_bottom.push_back(ly);
    B_top.push_back(ry);

    y_val.push_back(ly);
    y_val.push_back(ry);
    y_val.push_back(ly - 1);
    y_val.push_back(ry + 1);

    vec.push_back({lx, ly, rx, ry, 0, cnt});
    vec.push_back({rx, ry, lx, ly, 1, cnt});
  }

  sort(y_val.begin(), y_val.end());
  y_val.erase(unique(y_val.begin(), y_val.end()), y_val.end());

  auto get_y = [&](ll y) {
    return lower_bound(y_val.begin(), y_val.end(), y) - y_val.begin();
  };

  vec.push_back({0, 0, 0, 0, 1, 0});
  sort(vec.begin(), vec.end());

  Seg seg(0, (int)y_val.size() - 1);
  seg.update(0, (int)y_val.size() - 1, cnt + 1);

  v<v<ll>> dp(cnt + 2, v<ll>(2, 0));
  v<v<int>> nxt(cnt + 2, v<int>(2, cnt + 1));
  v<v<int>> take(cnt + 2, v<int>(2, -1));

  auto get_dist = [&](ll y, int hit, int &go) {
    if (hit == cnt + 1) {
      go = -1;
      return abs(y - dest_y);
    }

    ll cost_bottom = abs(y - (B_bottom[hit] - 1)) + dp[hit][0];
    ll cost_top = abs(y - (B_top[hit] + 1)) + dp[hit][1];

    if (cost_bottom <= cost_top) {
      go = 0;
      return cost_bottom;
    } else {
      go = 1;
      return cost_top;
    }
  };

  ll ans = (ll)4e18;
  int start_hit = cnt + 1, start_take = -1;

  for (auto it = vec.rbegin(); it != vec.rend(); ++it) {
    auto [cx, cy, ox, oy, type, idx] = *it;

    if (type == 1) {
      if (idx == 0) {
        int hit = seg.q(get_y(0));
        start_hit = hit;
        ans = dest_x + get_dist(0, hit, start_take);
      } else {
        ll y_bottom = oy;
        ll y_top = cy;

        int hit1 = seg.q(get_y(y_bottom - 1));
        nxt[idx][0] = hit1;
        dp[idx][0] = get_dist(y_bottom - 1, hit1, take[idx][0]);

        int hit2 = seg.q(get_y(y_top + 1));
        nxt[idx][1] = hit2;
        dp[idx][1] = get_dist(y_top + 1, hit2, take[idx][1]);
      }
    } else {
      ll y_bottom = cy;
      ll y_top = oy;
      seg.update(get_y(y_bottom), get_y(y_top), idx);
    }
  }

  v<pair<ll, ll>> moves;

  auto add_move = [&](ll dx, ll dy) {
    if (dx == 0 && dy == 0)
      return;

    if (!moves.empty()) {
      auto &[px, py] = moves.back();
      if (px == 0 && dx == 0) {
        py += dy;
        if (py == 0)
          moves.pop_back();
        return;
      }
      if (py == 0 && dy == 0) {
        px += dx;
        if (px == 0)
          moves.pop_back();
        return;
      }
    }

    moves.push_back({dx, dy});
  };

  ll cur_x = 0, cur_y = 0;
  int hit = start_hit, dir = start_take;

  while (hit != cnt + 1) {
    ll stop_x = B_left[hit] - 1;
    add_move(stop_x - cur_x, 0);
    cur_x = stop_x;

    ll need_y = (dir == 0 ? B_bottom[hit] - 1 : B_top[hit] + 1);
    add_move(0, need_y - cur_y);
    cur_y = need_y;

    ll nx = B_right[hit] + 1;
    add_move(nx - cur_x, 0);
    cur_x = nx;

    int ndir = take[hit][dir];
    int nhit = nxt[hit][dir];
    hit = nhit;
    dir = ndir;
  }

  add_move(dest_x - cur_x, 0);
  cur_x = dest_x;

  add_move(0, dest_y - cur_y);
  cur_y = dest_y;

  cout << ans << "\n";
  cout << moves.size() << "\n";
  for (auto [dx, dy] : moves)
    cout << dx << " " << dy << "\n";
}
#Verdict Execution timeMemoryGrader output
Fetching results...