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

// 線分の交差問題
#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <stack>

#include <queue>
#include <set>
#include <vector>

using namespace std;

// 浮動小数点のゼロ判定
#define EPS (1e-10)
#define equals(a, b) (fabs((a) - (b)) < EPS)

// 点を表すクラス
class Point {
public:
  double x, y;
  // コンストラクタ
  Point(double x = 0.0, double y = 0.0) : x(x), y(y) {}

  // -----▼▼▼ 演算子のオーバーロード ▼▼▼-----

  Point operator+(Point &p) { return Point(x + p.x, y + p.y); }

  Point operator-(Point &p) { return Point(x - p.x, y - p.y); }

  Point operator*(double a) { return Point(a * x, a * y); }

  Point operator/(double a) { return Point(x / a, y / a); }

  bool operator<(const Point &p) const { return x != p.x ? x < p.x : y < p.y; }

  bool operator<=(const Point &p) const {
    return x != p.x ? x <= p.x : y <= p.y;
  }

  bool operator==(const Point &p) const {
    return fabs(x - p.x) < EPS && fabs(y - p.y) < EPS;
  }

  // -----▲▲▲ 演算子のオーバーロード ▲▲▲-----

  // 2点間の距離の算出
  double distance() { return sqrt(norm()); }

  double norm() { return (x * x) + (y * y); }
};

// 線分を表すクラス
class Segment {
public:
  Point p1, p2;
  // コンストラクタ
  Segment(Point p1, Point p2) : p1(p1), p2(p2) {}
};

// 端点の種類
#define BOTTOM 0
#define LEFT 1
#define RIGHT 2
#define TOP 3

class EndPoint {
public:
  Point p;
  // 入力線分のID, 端点の種類
  int seg, st;

  EndPoint() {}
  EndPoint(Point p, int seg, int st) : p(p), seg(seg), st(st) {}

  bool operator<(const EndPoint &ep) const {
    // y座標が小さい順に整列
    if (p.y == ep.p.y) {
      // yが同一の場合は, 下端点, 左端点, 右端点, 上端点の順に並べる
      return st < ep.st;
    } else {
      return p.y < ep.p.y;
    }
  }
};

// 端点のリスト
EndPoint EP[2 * 100000];
// EndPoint EP[2 * 100];

// 線分交差問題　：　マンハッタン幾何
int manhattanIntersection(vector<Segment> S) {
  int n = S.size();

  for (int i = 0, k = 0; i < n; i++) {
    // 端点 p1, p2 が左下を基準に並ぶように調整
    if (S[i].p1.y == S[i].p2.y) {
      if (S[i].p1.x > S[i].p2.x) {
        swap(S[i].p1, S[i].p2);
      }
    } else if (S[i].p1.y > S[i].p2.y) {
      swap(S[i].p1, S[i].p2);
    }

    // 水平成分を端点リストに追加
    if (S[i].p1.y == S[i].p2.y) {
      EP[k++] = EndPoint(S[i].p1, i, LEFT);
      EP[k++] = EndPoint(S[i].p2, i, RIGHT);
    } else {
      // 垂直成分を端点リストに追加
      EP[k++] = EndPoint(S[i].p1, i, BOTTOM);
      EP[k++] = EndPoint(S[i].p2, i, TOP);
    }
  }

  // 端点の y 座標に関して昇順に整列
  sort(EP, EP + (2 * n));

  set<int> BT;           // 二分探索木
  BT.insert(1000000001); // 番兵を設置
  int cnt = 0;

  for (int i = 0; i < 2 * n; i++) {
    if (EP[i].st == TOP) {
      // 上端点を削除
      BT.erase(EP[i].p.x);
    } else if (EP[i].st == BOTTOM) {
      // 下端点を追加
      BT.insert(EP[i].p.x);
    } else if (EP[i].st == LEFT) {
      // O(log n)
      set<int>::iterator b = BT.lower_bound(S[EP[i].seg].p1.x);
      // O(log n)
      set<int>::iterator e = BT.upper_bound(S[EP[i].seg].p2.x);
      // b と e の距離(点の数)を加算, O(k)
      cnt += distance(b, e);
    }
  }

  return cnt;
}

int main(void) {

  int n, count;
  Point start, end;
  vector<Segment> v_segment;

  cin >> n;

  for (int i = 0; i < n; i++) {
    cin >> start.x >> start.y >> end.x >> end.y;

    // 線分の集合を作成
    Segment seg(start, end);

    v_segment.push_back(seg);
  }

  // 結果の表示
  count = manhattanIntersection(v_segment);
  printf("%d\\n", count);

  return 0;
}


Error: 0

Fixed submission:

// 線分の交差問題
#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <stack>

#include <queue>
#include <set>
#include <vector>

using namespace std;

// 浮動小数点のゼロ判定
#define EPS (1e-10)
#define equals(a, b) (fabs((a) - (b)) < EPS)

// 点を表すクラス
class Point {
public:
  double x, y;
  // コンストラクタ
  Point(double x = 0.0, double y = 0.0) : x(x), y(y) {}

  // -----▼▼▼ 演算子のオーバーロード ▼▼▼-----

  Point operator+(Point &p) { return Point(x + p.x, y + p.y); }

  Point operator-(Point &p) { return Point(x - p.x, y - p.y); }

  Point operator*(double a) { return Point(a * x, a * y); }

  Point operator/(double a) { return Point(x / a, y / a); }

  bool operator<(const Point &p) const { return x != p.x ? x < p.x : y < p.y; }

  bool operator<=(const Point &p) const {
    return x != p.x ? x <= p.x : y <= p.y;
  }

  bool operator==(const Point &p) const {
    return fabs(x - p.x) < EPS && fabs(y - p.y) < EPS;
  }

  // -----▲▲▲ 演算子のオーバーロード ▲▲▲-----

  // 2点間の距離の算出
  double distance() { return sqrt(norm()); }

  double norm() { return (x * x) + (y * y); }
};

// 線分を表すクラス
class Segment {
public:
  Point p1, p2;
  // コンストラクタ
  Segment(Point p1, Point p2) : p1(p1), p2(p2) {}
};

// 端点の種類
#define BOTTOM 0
#define LEFT 1
#define RIGHT 2
#define TOP 3

class EndPoint {
public:
  Point p;
  // 入力線分のID, 端点の種類
  int seg, st;

  EndPoint() {}
  EndPoint(Point p, int seg, int st) : p(p), seg(seg), st(st) {}

  bool operator<(const EndPoint &ep) const {
    // y座標が小さい順に整列
    if (p.y == ep.p.y) {
      // yが同一の場合は, 下端点, 左端点, 右端点, 上端点の順に並べる
      return st < ep.st;
    } else {
      return p.y < ep.p.y;
    }
  }
};

// 端点のリスト
// EndPoint EP[2 * 100000];
EndPoint EP[2 * 100];

// 線分交差問題　：　マンハッタン幾何
int manhattanIntersection(vector<Segment> S) {
  int n = S.size();

  for (int i = 0, k = 0; i < n; i++) {
    // 端点 p1, p2 が左下を基準に並ぶように調整
    if (S[i].p1.y == S[i].p2.y) {
      if (S[i].p1.x > S[i].p2.x) {
        swap(S[i].p1, S[i].p2);
      }
    } else if (S[i].p1.y > S[i].p2.y) {
      swap(S[i].p1, S[i].p2);
    }

    // 水平成分を端点リストに追加
    if (S[i].p1.y == S[i].p2.y) {
      EP[k++] = EndPoint(S[i].p1, i, LEFT);
      EP[k++] = EndPoint(S[i].p2, i, RIGHT);
    } else {
      // 垂直成分を端点リストに追加
      EP[k++] = EndPoint(S[i].p1, i, BOTTOM);
      EP[k++] = EndPoint(S[i].p2, i, TOP);
    }
  }

  // 端点の y 座標に関して昇順に整列
  sort(EP, EP + (2 * n));

  set<int> BT;           // 二分探索木
  BT.insert(1000000001); // 番兵を設置
  int cnt = 0;

  for (int i = 0; i < 2 * n; i++) {
    if (EP[i].st == TOP) {
      // 上端点を削除
      BT.erase(EP[i].p.x);
    } else if (EP[i].st == BOTTOM) {
      // 下端点を追加
      BT.insert(EP[i].p.x);
    } else if (EP[i].st == LEFT) {
      // O(log n)
      set<int>::iterator b = BT.lower_bound(S[EP[i].seg].p1.x);
      // O(log n)
      set<int>::iterator e = BT.upper_bound(S[EP[i].seg].p2.x);
      // b と e の距離(点の数)を加算, O(k)
      cnt += distance(b, e);
    }
  }

  return cnt;
}

int main(void) {

  int n, count;
  Point start, end;
  vector<Segment> v_segment;

  cin >> n;

  for (int i = 0; i < n; i++) {
    cin >> start.x >> start.y >> end.x >> end.y;

    // 線分の集合を作成
    Segment seg(start, end);

    v_segment.push_back(seg);
  }

  // 結果の表示
  count = manhattanIntersection(v_segment);
  printf("%d\\n", count);

  return 0;
}