Problem p00858 (C++) — buggy submission, verdict: Runtime Error

#include <algorithm>
#include <array>
#include <assert.h>
#include <bitset>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstring>
#include <deque>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <random>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <vector>

using namespace std;

#define REP(i, a, b) for (int i = a; i < (int)b; i++)
#define rep(i, n) REP(i, 0, n)
#define all(c) (c).begin(), (c).end()
#define zero(a) memset(a, 0, sizeof a)
#define minus(a) memset(a, -1, sizeof a)
#define watch(a)                                                               \\
  { cout << #a << " = " << a << endl; }
template <class T1, class T2> inline bool minimize(T1 &a, T2 b) {
  return b < a && (a = b, 1);
}
template <class T1, class T2> inline bool maximize(T1 &a, T2 b) {
  return a < b && (a = b, 1);
}

typedef long long ll;
int const inf = 1 << 29;

struct xor128 {
  unsigned x, y, z, w;
  xor128() : x(random_device()()), y(157892372), z(7777777), w(757328) {}
  unsigned next() {
    unsigned t = x ^ (x << 11);
    x = y;
    y = z;
    z = w;
    return w = w ^ (w >> 19) ^ t ^ (t >> 8);
  }
  unsigned next(unsigned k) { return next() % k; }
} rndgen;

typedef complex<double> P;

namespace std {

bool operator<(P const &l, P const &r) {
  return abs(l.real() - r.real()) < 1e-5 ? l.imag() < r.imag()
                                         : l.real() < r.real();
}

} // namespace std

namespace point_2d {

using Real = double;

Real const EPS = 1e-5; // !!! DO CHECK EPS !!!

// bool operator < (P const& l, P const& r) {  return abs(l.real() - r.real()) <
// EPS ? l.imag() < r.imag() : l.real() < r.real();}

bool operator>(P const &l, P const &r) {
  return abs(l.real() - r.real()) < EPS ? l.imag() > r.imag()
                                        : l.real() > r.real();
}

bool equals(Real a, Real b) { return abs(a - b) < EPS; }

bool equals(P const &l, P const &r) { return abs(l - r) < EPS; }

struct Line : public pair<P, P> {
  Line(P const &a, P const &b) { first = a, second = b; }
  const P &operator[](int x) const { return x == 0 ? first : second; }
  P &operator[](int x) { return x == 0 ? first : second; }
};
typedef Line Segment;

bool operator<(const Line &a, const Line &b) {
  return a[0] != b[0] ? a[0] < b[0] : a[1] < b[1];
}

struct Circle {
  P p;
  Real r;
  Circle() {}
  Circle(P const &p, Real r) : r(r) { this->p = p; }
};

struct Polygon : public vector<P> {
  vector<P> &g = *this;
  Polygon() = default;
  Polygon(vector<P> const &g) { this->g = g; }
  P &operator[](int x) { return vector<P>::operator[]((x + size()) % size()); }
  Segment side(int x) {
    return std::move(Segment(this->operator[](x), this->operator[](x + 1)));
  }
  Segment backside(int x) {
    return std::move(Segment(this->operator[](x), this->operator[](x - 1)));
  }
};

Real cross(P const &a, P const &b) { return imag(conj(a) * b); }
Real dot(P const &a, P const &b) { return real(conj(a) * b); }
Real cos(P const &l, P const &r) {
  return dot(l, r) / (abs(l) * abs(r));
} // not verified

enum ccw_result {
  counter_clockwise = +1,
  clockwise = -1,
  online_back = +2,
  online_front = -2,
  on_segment = 0
};

ccw_result ccw(P a, P b, P c) {
  b -= a, c -= a;
  if (cross(b, c) > 0) {
    return ccw_result::counter_clockwise;
  }
  if (cross(b, c) < 0) {
    return ccw_result::clockwise;
  }
  if (dot(b, c) < 0) {
    return ccw_result::online_back;
  }
  if (norm(b) < norm(c)) {
    return ccw_result::online_front;
  }
  return ccw_result::on_segment;
}

bool intersect_lp(Line const &l, P const &p) {
  return abs(cross(l[1] - p, l[0] - p)) < EPS;
}

bool intersect_sp(Line const &s, P const &p) {
  return abs(s[0] - p) + abs(s[1] - p) - abs(s[1] - s[0]) <
         EPS; // triangle inequality
}

bool intersect_ss(Segment const &s, Segment const &t) {
  return ccw(s[0], s[1], t[0]) * ccw(s[0], s[1], t[1]) <= EPS &&
         ccw(t[0], t[1], s[0]) * ccw(t[0], t[1], s[1]) <= EPS;
}

bool intersect_ll(Line const &l, Line const &m) {
  return abs(cross(l[1] - l[0], m[1] - m[0])) > EPS || // non-parallel
         abs(cross(l[1] - l[0], m[0] - l[0])) < EPS;   // same line
}

bool intersect_ls(Line const &l, Segment const &s) {
  return cross(l[1] - l[0], s[0] - l[0]) * // s[0] is left of l
             cross(l[1] - l[0], s[1] - l[0]) <
         EPS; // s[1] is right of l
}

P projection(Line const &l, P const &p) {
  auto t = dot(p - l[0], l[0] - l[1]) / norm(l[0] - l[1]);
  return l[0] + t * (l[0] - l[1]);
}

P reflection(Line const &l, P const &p) {
  return p + (Real)2.0 * (projection(l, p) - p);
}

Real distance_sp(Line const &s, P const &p) {
  P const r = projection(s, p);
  if (intersect_sp(s, r))
    return abs(r - p);
  return min(abs(s[0] - p), abs(s[1] - p));
}

Real distance_lp(Line const &l, P const &p) {
  return abs(p - projection(l, p));
}

bool intersect_cl(Circle const &c, Line const &l) {
  return distance_lp(l, c.p) <= c.r + EPS;
}

bool intersect_cs(Circle const &c, Line const &l) {
  if (abs(l[0] - c.p) < c.r - EPS && abs(l[1] - c.p) < c.r - EPS) {
    return false;
  }
  return distance_lp(l, c.p) <= c.r + EPS;
}

bool intersect_gs(Polygon const &g, Segment const &s) { // not verified
  auto u = const_cast<Polygon &>(g);
  rep(i, g.size()) {
    if (!intersect_sp(s, u[i]) && intersect_ss(s, u.side(i))) {
      return true;
    }
  }
  return false;
}

P crosspoint(const Line &l, const Line &m) {
  auto A = cross(l[1] - l[0], m[1] - m[0]);
  auto B = cross(l[1] - l[0], l[1] - m[0]);
  if (abs(A) < EPS && abs(B) < EPS)
    return m[0]; // same line
  if (abs(A) < EPS)
    assert(false && "PRECONDITION NOT SATISFIED");
  return m[0] + B / A * (m[1] - m[0]);
}

pair<P, P> crosspoint(Circle const &c, Line const &l) {
  auto h = projection(l, c.p);
  auto e = (l[1] - l[0]) / abs(l[1] - l[0]);
  auto base = sqrt(c.r * c.r - abs(h - c.p) * abs(h - c.p));
  return {h + e * base, h - e * base};
}

pair<P, P> crosspoint(Circle c1, Circle c2) {
  if (c1.p.real() > c2.p.real())
    swap(c1, c2);
  auto const d = abs(c2.p - c1.p);
  auto const alpha = acos((c2.p.real() - c1.p.real()) / d) *
                     ((c1.p.imag() > c2.p.imag()) ? -1.0 : 1.0);
  auto const beta = acos((c1.r * c1.r - c2.r * c2.r + d * d) / 2.0 / d / c1.r);
  return make_pair(c1.p + polar(c1.r, alpha - beta),
                   c1.p + polar(c1.r, alpha + beta));
}

vector<P> tangent_points(Circle const &c, P const &p) {
  vector<P> ret;
  auto const sec2 = norm(p - c.p);
  auto const tan2 = max(Real(0), sec2 - c.r * c.r);
  auto const nv = (p - c.p) * c.r * c.r / sec2;
  auto const pv = (p - c.p) * P(0, -1) * c.r * sqrt(tan2) / sec2;
  ret.push_back(c.p + nv + pv);
  ret.push_back(c.p + nv - pv);
  return ret;
}

// テゥツ?堙・ツクツクclangテ」ツ?ァテ」ツ?づ」ツつ古」ツ?ーテ」ツ??(x,
// y)"テ」ツ?ョテ・ツスツ「テ・ツシツ湘」ツつ津ィツェツュテ」ツ?ソテ・ツ渉姪」ツつ凝」ツ?古」ツ??」ツ?禿」ツつ古」ツつ?x
// y"テ」ツ?ォテ・ツ、ツ嘉ヲツ崢エテ」ツ?凖」ツつ?
istream &operator>>(istream &is, P &p) {
  Real x, y;
  is >> x >> y;
  p = P(x, y);
  return is;
}
ostream &operator<<(ostream &os, Line const &l) {
  return os << "{" << l[0] << ", " << l[1] << "}";
}

} // namespace point_2d
using namespace point_2d;

int N;
P src, dst;
vector<Line> line;
vector<vector<pair<int, double>>> G;
map<pair<int, int>, int> nd;
map<int, P> ndB;
int nsize;

template <class T> using PQ_G = priority_queue<T, vector<T>, greater<T>>;

void dijkstra(int s, int t) {

  vector<double> dist(222, inf);
  vector<int> prev(222, inf);
  dist[s] = 0;

  PQ_G<pair<double, int>> pq;
  pq.emplace(0, s);

  while (!pq.empty()) {
    double len;
    int pos;
    tie(len, pos) = pq.top();
    pq.pop();
    for (auto const &e : G[pos]) {
      int next;
      double plen;
      tie(next, plen) = e;
      //      cout << pos << " -> " << next << endl;
      if (dist[next] <= len + plen)
        continue;
      dist[next] = len + plen;
      prev[next] = pos;
      pq.emplace(dist[next], next);
    }
  }

  //  cout << s << ", " << t << endl;  cout << dist[s] << ", " << dist[t] <<
  //  endl;

  if (dist[t] == inf) {
    cout << -1 << endl;
  } else {
    vector<pair<int, int>> path;
    for (int pos = t; pos != s; pos = prev[pos]) {
      assert(pos != inf);
      path.emplace_back((int)ndB[pos].real(), (int)ndB[pos].imag());
    }
    cout << (int)ndB[s].real() << " " << (int)ndB[s].imag() << endl;
    //    cout << s << endl;
    reverse(all(path));
    for (auto &e : path)
      cout << e.first << " " << e.second << endl;
    //      cout << nd[e] << endl;
    cout << "0\\n";
  }
}

bool merge_if_able(Line &s, Line t) {
  if (abs(cross(s[1] - s[0], t[1] - t[0])) > EPS)
    return false;
  if (ccw(s[0], t[0], s[1]) == +1 || ccw(s[0], t[0], s[1]) == -1)
    return false; // not on the same line
  if (ccw(s[0], s[1], t[0]) == -2 || ccw(t[0], t[1], s[0]) == -2)
    return false; // separated
  s = Line(min(s[0], t[0]), max(s[1], t[1]));
  return true;
}
void merge_segments(vector<Line> &segs) {
  for (int i = 0; i < segs.size(); ++i)
    if (segs[i][1] < segs[i][0])
      swap(segs[i][1], segs[i][0]);
  for (int i = 0; i < segs.size(); ++i)
    for (int j = i + 1; j < segs.size(); ++j)
      if (merge_if_able(segs[i], segs[j]))
        segs[j--] = segs.back(), segs.pop_back();
}

void split_segments(vector<Line> &segs, vector<P> const &pts) {
  vector<Line> nsegs;
  rep(i, segs.size()) {
    vector<P> v = {segs[i][0], segs[i][1]};
    rep(j, pts.size()) {
      if (intersect_sp(segs[i], pts[j]) && !equals(segs[i][0], pts[j]) &&
          !equals(segs[i][1], pts[j])) {
        //        cout << "check" << endl;
        v.push_back(pts[j]);
      }
    }
    sort(all(v));
    rep(i, v.size() - 1) { nsegs.push_back(Line(v[i], v[i + 1])); }
  }

  segs = nsegs;
}

void solve() {

  double x, y;
  cin >> x >> y;
  src = P(x, y);
  cin >> x >> y;
  dst = P(x, y);

  rep(i, N) {
    P p1;
    cin >> x >> y;
    p1 = P(x, y);
    P p2;
    cin >> x >> y;
    p2 = P(x, y);
    line.push_back(Line(p1, p2));
  }

  map<pair<int, int>, int> cnt;
  rep(i, N) {
    REP(j, i + 1, N) {
      if (intersect_ss(line[i], line[j])) {
        auto p = crosspoint(line[i], line[j]);
        cnt[{p.real(), p.imag()}]++;
      }
    }
  }

#define reg_node(node)                                                         \\
  { nd[{node.real(), node.imag()}] = nsize, ndB[nsize++] = node; }

  reg_node(src);
  reg_node(dst);

#define new_node(p) nd.find({p.real(), p.imag()}) == nd.end()

  rep(i, N) {
    auto p = line[i][0];
    auto q = line[i][1];
    if (cnt[{p.real(), p.imag()}] > 0 && cnt[{q.real(), q.imag()}] > 0) {
      if (new_node(p))
        reg_node(p);
      if (new_node(q))
        reg_node(q);
    }
  }

#define road(l)                                                                \\
  (nd.find({l[0].real(), l[0].imag()}) != nd.end() &&                          \\
   nd.find({l[1].real(), l[1].imag()}) != nd.end())

  vector<Line> nl;

  set<int> del;

  rep(i, N) {
    if (road(line[i])) {
      REP(j, i + 1, N) {
        if (road(line[j])) {
          if (intersect_ss(line[i], line[j])) {
            auto cp = crosspoint(line[i], line[j]);
            if (new_node(cp))
              reg_node(cp);
            if (!(equals(cp, line[i][0]) || equals(cp, line[i][1])) &&
                (equals(cp, line[j][0]) || equals(cp, line[j][1]))) {
              nl.push_back(Line(line[i][0], cp));
              nl.push_back(Line(line[i][1], cp));
              del.insert(i);
            } else if ((equals(cp, line[i][0]) || equals(cp, line[i][1])) &&
                       !(equals(cp, line[j][0]) || equals(cp, line[j][1]))) {
              nl.push_back(Line(line[j][0], cp));
              nl.push_back(Line(line[j][1], cp));
              del.insert(j);
            } else /*if((equals(cp, line[i][0]) || equals(cp, line[i][1])) &&
  //               (equals(cp, line[j][0]) || equals(cp, line[j][1])))*/
            {
            }
          }
        }
      }
    }
  }

  vector<Line> signs;

  rep(i, N) {
    if (road(line[i]) && !del.count(i))
      nl.push_back(line[i]);
    if (!road(line[i])) {
      auto sign = line[i];
      rep(k, line.size()) {
        if (road(line[k]) && intersect_ss(line[k], sign)) {
          auto cp = crosspoint(line[k], sign);
          if (equals(sign[1], cp))
            swap(sign[0], sign[1]);
          signs.push_back(sign);
          break;
        }
      }
    }
  }

  merge_segments(nl);
  vector<P> pts;
  for (auto &e : nd)
    pts.push_back(P(e.first.first, e.first.second));
  split_segments(nl, pts);

  sort(all(nl));
  nl.erase(unique(all(nl)), nl.end());
  /*
    visualizer::init();  drawlines(nl);  drawlines(signs);

    for(auto& e: nd) {
      P k = P(e.first.first, e.first.second);
      visualizer::point(k);
      visualizer::label(k, to_string(nd[{k.real(),k.imag()}]));
    }
  */

#define corresponds_sign(r, s) intersect_ss(r, s)

  auto can_go = [&](P p, P s, P o) { return dot(p - s, o - s) > EPS; };

  set<pair<int, int>> invalids;

  rep(i, nl.size()) {
    rep(j, signs.size()) {
      if (corresponds_sign(nl[i], signs[j])) {
        auto &tar = nl[i];
        auto &sign = signs[j];
        if (!can_go(tar[0], sign[0], sign[1]))
          invalids.insert({nd[{tar[0].real(), tar[0].imag()}],
                           nd[{tar[1].real(), tar[1].imag()}]});

        if (!can_go(tar[1], sign[0], sign[1]))
          invalids.insert({nd[{tar[1].real(), tar[1].imag()}],
                           nd[{tar[0].real(), tar[0].imag()}]});
      }
    }
  }

  rep(i, nl.size()) {
    auto &tar = nl[i];
    auto s = nd[{tar[0].real(), tar[0].imag()}];
    auto t = nd[{tar[1].real(), tar[1].imag()}];
    if (!invalids.count({s, t}))
      G[s].emplace_back(t, abs(tar[0] - tar[1]));
    if (!invalids.count({t, s}))
      G[t].emplace_back(s, abs(tar[0] - tar[1]));
  }

  //  graph::visualizer::directed_graph(G);  visualizer::show_picture();

  dijkstra(nd[{src.real(), src.imag()}], nd[{dst.real(), dst.imag()}]);
}

void init() {
  line.clear();
  G.resize(222);
  rep(i, 222) G[i].clear();
  nsize = 0;
  nd.clear();
  ndB.clear();
}

int main() {
  while (cin >> N && N) {
    init();
    solve();
  }
}

Error: 0

Fixed submission:


#include <bits/stdc++.h>

// -----------------------------------------------------------------------
// commonly used template
#if !defined commonly_used_template
#define commonly_used_template

#define REP(i, a, b) for (int i = a; i < (int)b; i++)
#define rep(i, n) REP(i, 0, n)

#define EPS (1e-7)
int const INF = 1 << 29;

#endif
// -----------------------------------------------------------------------

using namespace std;

#define fi first
#define se second

// ------------------------------------------------------
// common graph
#if !defined common_graph
#define common_graph

struct Edge {
  int to;
  double cost;
};
typedef std::vector<Edge> Edges;
typedef std::vector<Edges> Graph;

#endif
// ------------------------------------------------------

// -----------------------------------------------------------------------
// common geometry
#if !defined common_geometry
#define common_geometry

typedef complex<double> P;
typedef complex<int> IntP;

bool is_equal(P const &a, P const &b) {
  if (abs(a - b) < EPS)
    return true;
  return false;
}

namespace std {
bool operator<(P const &a, P const &b) {
  if (a.real() != b.real())
    return a.real() < b.real();
  return a.imag() < b.imag();
}

bool operator<(IntP const &a, IntP const &b) {
  if (a.real() != b.real())
    return a.real() < b.real();
  return a.imag() < b.imag();
}

bool operator==(P const &a, P const &b) { return is_equal(a, b); }
} // namespace std

double dot(P const &a, P const &b) { return real(conj(a) * b); }

double cross(P const &a, P const &b) { return imag(conj(a) * b); }

struct Circle {
  P p;
  double r;
  Circle(P const &p, double r) : p(p), r(r) {}
};

struct Line : public vector<P> {
  Line() { resize(2); }
  Line(P const &a, P const &b) { push_back(a), push_back(b); }
  double length() { return abs((*this)[0] - (*this)[1]); }
  P vectorize() { return (*this)[1] - (*this)[0]; }
};
ostream &operator<<(ostream &ost, Line const &ln) {
  return ost << "{" << ln[0] << ", " << ln[1] << "}";
}

int ccw(P a, P b, P c) {
  b -= a;
  c -= a;
  if (cross(b, c) > 0)
    return +1;
  if (cross(b, c) < 0)
    return -1;
  if (dot(b, c) < 0)
    return +2;
  if (norm(b) < norm(c))
    return -2;
  return 0;
}

bool is_cross(Line const &s, Line const &t) {
  return (ccw(s[0], s[1], t[0]) * ccw(s[0], s[1], t[1]) < EPS) &&
         (ccw(t[0], t[1], s[0]) * ccw(t[0], t[1], s[1]) < EPS);
}

P crosspoint(Line const &a, Line const &b) {
  double k = cross(a[1] - a[0], b[1] - b[0]);
  double t = cross(a[1] - a[0], a[1] - b[0]);
  if (abs(k) < EPS && abs(t) < EPS)
    return b[0];
  return b[0] + t / k * (b[1] - b[0]);
}

#endif
// -----------------------------------------------------------------------

set<int> is_signsw;

int id_size;
vector<int> deg;
map<int, P> to_point;
map<P, int> to_id;

typedef pair<int, bool> PathNode;
vector<int> prev_path;
vector<double> dist;

Graph g;

double dijkstra(Graph const &g, int S, int T) {

  prev_path.resize(id_size);
  prev_path[S] = -1;

  dist.resize(id_size);

  rep(i, dist.size()) dist[i] = INF;
  dist[S] = 0.;

  typedef pair<double, int> Pdi;

  priority_queue<Pdi> pq;
  pq.push(Pdi(dist[S], S));
  while (!pq.empty()) {
    Pdi pdi = pq.top();
    pq.pop();
    double const cost = -pdi.fi;
    int pos = pdi.se;

    if (pos == T)
      return cost;

    rep(i, g[pos].size()) {
      Edge const &e = g[pos][i];
      if (e.to == -1) {
        continue;
      } // 通過不可のため削除された道
      if (dist[e.to] <= cost + e.to) {
        continue;
      }
      dist[e.to] = cost + e.to;
      pq.push(Pdi(-dist[e.to], e.to));
      prev_path[e.to] = pos;
    }
  }

  return INF;
}

vector<Line> subdivide_lines(vector<Line> const &lines) {
  vector<Line> ret;
  rep(i, lines.size()) {
    set<Line> st;
    Line const &me = lines[i];

    vector<P> vs;
    vs.push_back(me[0]);
    vs.push_back(me[1]);
    rep(j, lines.size()) {
      if (i == j) {
        continue;
      }
      bool crossed = 0;
      Line const &tg = lines[j];
      if (is_cross(me, tg)) {
        P cp = crosspoint(me, tg);
        if (is_equal(me[0], cp) || is_equal(me[1], cp)) {
          continue;
        } // 交点が自分の線分の端点の場合を除外
        crossed = 1;
        vs.push_back(crosspoint(me, tg));
      }
    }

    sort(vs.begin(), vs.end());

    rep(i, (int)vs.size() - 1) { st.insert(Line(vs[i], vs[i + 1])); }

    for (auto i : st) {
      ret.push_back(i);
    }
  }

  return ret;
}

void init_global() {
  is_signsw.clear();
  to_point.clear();
  to_id.clear();
  g.clear();
  deg.clear();
  prev_path.clear();
  dist.clear();
}

int main() {
  int N;
  int xs, ys, xg, yg;
  while (cin >> N && N) {
    init_global();

    set<P> intersections;
    cin >> xs >> ys >> xg >> yg;
    intersections.insert(P(xs, ys));
    intersections.insert(P(xg, yg));
    vector<Line> raw_lines;
    rep(i, N) {
      int x1, y1, x2, y2;
      cin >> x1 >> y1 >> x2 >> y2;
      intersections.insert(P(x1, y1));
      intersections.insert(P(x2, y2));
      raw_lines.push_back(Line(P(x1, y1), P(x2, y2)));
    }

    vector<Line> lines = subdivide_lines(raw_lines);

    typedef pair<int, int> Pii;
    set<Pii> st; // 新規ノード追加用

    id_size = 0;
    rep(i, lines.size()) {
      Line &ln = lines[i];
      rep(k, 2) {
        Pii LNK = Pii((int)ln[k].real(), (int)ln[k].imag());
        if (!st.count(LNK)) {
          to_point[id_size] = ln[k];
          to_id[ln[k]] = id_size;
          id_size++;
          g.resize(id_size);
          deg.resize(id_size);
          st.insert(LNK);
        }
      }
      int s = to_id[ln[0]], t = to_id[ln[1]];
      g[s].push_back((Edge){t, ln.length()});
      g[t].push_back((Edge){s, ln.length()});
      deg[s]++, deg[t]++;
    }

    rep(i, id_size) {
      rep(j, g[i].size()) {
        Edge const &e = g[i][j];
        if (e.to == -1) {
          continue;
        }
        if (deg[e.to] != 1) {
          continue;
        }

        // 標識の分岐点を登録
        is_signsw.insert(i);

        rep(k, g[i].size()) {
          Edge const &f = g[i][k];
          if (e.to == f.to) {
            continue;
          }

          P sign_end = to_point[e.to];
          P swpoint = to_point[i];
          P come = to_point[f.to];
          sign_end -= swpoint, come = swpoint - come;

          if (dot(sign_end, come) > -EPS) {
            // come -> 標識の分岐点 の道を削除する
            rep(ii, g[f.to].size()) {
              if (g[f.to][ii].to == i) {
                g[f.to][ii].to = -1;
                break;
              }
            }
          }
        }
      }
    }

    int S = to_id[P(xs, ys)], T = to_id[P(xg, yg)];

    // dijkstra
    int ans = dijkstra(g, S, T);
    if (ans == INF) {
      cout << -1 << endl;
    } else {
      vector<pair<int, int>> path;
      int now = T;
      for (; now != S; now = prev_path[now]) {
        if (is_signsw.count(now)) {
          continue;
        }
        P &p = to_point[now];
        if (!intersections.count(p)) {
          continue;
        }
        path.push_back(make_pair(p.real(), p.imag()));
      }
      path.push_back(make_pair(xs, ys));
      reverse(path.begin(), path.end());
      rep(i, path.size()) { cout << path[i].fi << " " << path[i].se << endl; }
      cout << 0 << endl;
    }
  }

  return 0;
}