Problem:
Segment Intersections: Manhattan Geometry
For given $n$ segments which are parallel to X-axis or Y-axis, find the number of intersections of them.
Input
In the first line, the number of segments $n$ is given. In the following $n$ lines, the $i$-th segment is given by coordinates of its end points in the following format:
$x_1 \; y_1 \; x_2 \; y_2$
The coordinates are given in integers.
Output
Print the number of intersections in a line.
Constraints
$1 \leq n \leq 100,000$
$ -1,000,000,000 \leq x_1, y_1, x_2, y_2 \leq 1,000,000,000$
Two parallel segments never overlap or touch.
The number of intersections  $\leq 1,000,000$
Sample Input 1
6
2 2 2 5
1 3 5 3
4 1 4 4
5 2 7 2
6 1 6 3
6 5 6 7
Sample Output 1
3

Submitted solutions:

code_snippet: // --- Start of include: ./../../akakoi_lib/template/template.cpp ---
// #pragma GCC target("avx2")
// #pragma GCC optimize("O3,unroll-loops")
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i,n) for(ll i=0;i<(ll)(n);++i)
bool chmin(auto& a, auto b) {return a>b?a=b,1:0;}
bool chmax(auto& a, auto b) {return a<b?a=b,1:0;}
// int main() {
//     ios::sync_with_stdio(false);
//     cin.tie(0);
// }
// --- End of include: ./../../akakoi_lib/template/template.cpp ---
// --- Start of include: ./../../akakoi_lib/geometry/geometry.cpp ---
/// @brief 幾何ライブラリ
namespace Geometry {
 using Real = long double;
 const Real EPS = 1e-9;

 bool almostEqual(Real a, Real b) { return abs(a - b) < EPS; }
 bool lessThan(Real a, Real b) { return a < b && !almostEqual(a, b); }
 bool greaterThan(Real a, Real b) { return a > b && !almostEqual(a, b); }
 bool lessThanOrEqual(Real a, Real b) { return a < b || almostEqual(a, b); }
 bool greaterThanOrEqual(Real a, Real b) { return a > b || almostEqual(a, b); }

 /// @brief ２次元平面上の位置ベクトル
 struct Point {
  Real x, y;
  Point() = default;
  Point(Real x, Real y) : x(x), y(y) {}

  Point operator+(const Point& p) const { return Point(x + p.x, y + p.y); }
  Point operator-(const Point& p) const { return Point(x - p.x, y - p.y); }
  Point operator*(Real k) const { return Point(x * k, y * k); }
  Point operator/(Real k) const { return Point(x / k, y / k); }

  /// @brief p との内積を返す
  Real dot(const Point& p) const { return x * p.x + y * p.y; }

  /// @brief p との外積を返す
  Real cross(const Point& p) const { return x * p.y - y * p.x; }

  /// @brief p1 と p2 を端点とするベクトルとの外積を返す
  Real cross(const Point& p1, const Point& p2) const { return (p1.x - x) * (p2.y - y) - (p1.y - y) * (p2.x - x); }

  /// @brief ２乗ノルムを返す
  Real norm() const { return x * x + y * y; }

  /// @brief ユークリッドノルムを返す
  Real abs() const { return sqrt(norm()); }

  /// @brief 偏角を返す
  Real arg() const { return atan2(y, x); }

  bool operator==(const Point& p) const { return almostEqual(x, p.x) && almostEqual(y, p.y); }
  friend istream& operator>>(istream& is, Point& p) { return is >> p.x >> p.y; }
 };

 /// @brief 直線
 struct Line {
  Point a, b;
  Line() = default;
  Line(const Point& _a, const Point& _b) : a(_a), b(_b) {}

  /// @brief 直線 Ax+By=C を定義する
  Line(const Real& A, const Real& B, const Real& C) {
   if (almostEqual(A, 0)) {
    assert(!almostEqual(B, 0));
    a = Point(0, C / B);
    b = Point(1, C / B);
   } else if (almostEqual(B, 0)) {
    a = Point(C / A, 0);
    b = Point(C / A, 1);
   } else if (almostEqual(C, 0)) {
    a = Point(0, C / B);
    b = Point(1, (C - A) / B);
   } else {
    a = Point(0, C / B);
    b = Point(C / A, 0);
   }
  }

  bool operator==(const Line& l) const { return a == l.a && b == l.b; }
  friend istream& operator>>(istream& is, Line& l) { return is >> l.a >> l.b; }
 };

 /// @brief 線分
 struct Segment : Line {
  Segment() = default;
  using Line::Line;
 };

 /// @brief 円
 struct Circle {
  Point center;  ///< 中心
  Real r;  ///< 半径

  Circle() = default;
  Circle(Real x, Real y, Real r) : center(x, y), r(r) {}
  Circle(Point _center, Real r) : center(_center), r(r) {}

  bool operator==(const Circle& C) const { return center == C.center && r == C.r; }
  friend istream& operator>>(istream& is, Circle& C) { return is >> C.center >> C.r; }
 };

 //-----------------------------------------------------------

 /// @brief 3点の進行方向
 enum Orientation {
  COUNTER_CLOCKWISE,  ///< 反時計回り
  CLOCKWISE,  ///< 時計回り
  ONLINE_BACK,
  ONLINE_FRONT,
  ON_SEGMENT
 };

 /// @brief 3点 p0, p1, p2 の進行方向を返す
 Orientation ccw(const Point& p0, const Point& p1, const Point& p2) {
  Point a = p1 - p0;
  Point b = p2 - p0;
  Real cross_product = a.cross(b);
  if (greaterThan(cross_product, 0)) return COUNTER_CLOCKWISE;
  if (lessThan(cross_product, 0)) return CLOCKWISE;
  if (lessThan(a.dot(b), 0)) return ONLINE_BACK;
  if (lessThan(a.norm(), b.norm())) return ONLINE_FRONT;
  return ON_SEGMENT;
 }

 string orientationToString(Orientation o) {
  switch (o) {
   case COUNTER_CLOCKWISE:
    return "COUNTER_CLOCKWISE";
   case CLOCKWISE:
    return "CLOCKWISE";
   case ONLINE_BACK:
    return "ONLINE_BACK";
   case ONLINE_FRONT:
    return "ONLINE_FRONT";
   case ON_SEGMENT:
    return "ON_SEGMENT";
   default:
    return "UNKNOWN";
  }
 }

 /// @brief ベクトル p の直線 p1, p2 への正射影ベクトルを返す
 Point projection(const Point& p1, const Point& p2, const Point& p) {
  Point base = p2 - p1;
  Real r = (p - p1).dot(base) / base.norm();
  return p1 + base * r;
 }

 /// @brief ベクトル p の直線 l への正射影ベクトルを返す
 Point projection(const Line& l, const Point& p) {
  Point base = l.b - l.a;
  Real r = (p - l.a).dot(base) / base.norm();
  return l.a + base * r;
 }

 /// @brief ベクトル p の直線 p1, p2 に対する鏡像ベクトルを返す
 Point reflection(const Point& p1, const Point& p2, const Point& p) {
  Point proj = projection(p1, p2, p);
  return proj * 2 - p;
 }

 /// @brief ベクトル p の直線 l に対する鏡像ベクトルを返す
 Point reflection(const Line& l, const Point& p) {
  Point proj = projection(l, p);
  return proj * 2 - p;
 }

 //-----------------------------------------------------------

 /// @brief 直線の平行判定
 bool isParallel(const Line& l1, const Line& l2) { return almostEqual((l1.b - l1.a).cross(l2.b - l2.a), 0); }
 /// @brief 直線の直交判定
 bool isOrthogonal(const Line& l1, const Line& l2) { return almostEqual((l1.b - l1.a).dot(l2.b - l2.a), 0); }
 /// @brief 線分の平行判定
 bool isParallel(const Segment& l1, const Segment& l2) { return almostEqual((l1.b - l1.a).cross(l2.b - l2.a), 0); }
 /// @brief 線分の直交判定
 bool isOrthogonal(const Segment& l1, const Segment& l2) { return almostEqual((l1.b - l1.a).dot(l2.b - l2.a), 0); }
 /// @brief 直線と線分の平行判定
 bool isParallel(const Line& l1, const Segment& l2) { return almostEqual((l1.b - l1.a).cross(l2.b - l2.a), 0); }
 /// @brief 直線と線分の直交判定
 bool isOrthogonal(const Line& l1, const Segment& l2) { return almostEqual((l1.b - l1.a).dot(l2.b - l2.a), 0); }
 /// @brief 線分と直線の平行判定
 bool isParallel(const Segment& l1, const Line& l2) { return almostEqual((l1.b - l1.a).cross(l2.b - l2.a), 0); }
 /// @brief 線分と直線の直交判定
 bool isOrthogonal(const Segment& l1, const Line& l2) { return almostEqual((l1.b - l1.a).dot(l2.b - l2.a), 0); }
 /// @brief 点が直線上にあるか判定
 bool isPointOnLine(const Point& p, const Line& l) { return almostEqual((l.b - l.a).cross(p - l.a), 0.0); }

 /// @brief 点が線分上にあるか判定
 bool isPointOnSegment(const Point& p, const Segment& s) {
  return lessThanOrEqual(min(s.a.x, s.b.x), p.x) &&
     lessThanOrEqual(p.x, max(s.a.x, s.b.x)) &&
     lessThanOrEqual(min(s.a.y, s.b.y), p.y) &&
     lessThanOrEqual(p.y, max(s.a.y, s.b.y)) &&
     almostEqual((s.b - s.a).cross(p - s.a), 0.0);
 }

 /// @brief 直線の交差判定
 bool isIntersecting(const Segment& s1, const Segment& s2) {
  Point p0p1 = s1.b - s1.a, p0p2 = s2.a - s1.a, p0p3 = s2.b - s1.a, p2p3 = s2.b - s2.a, p2p0 = s1.a - s2.a, p2p1 = s1.b - s2.a;
  Real d1 = p0p1.cross(p0p2), d2 = p0p1.cross(p0p3), d3 = p2p3.cross(p2p0), d4 = p2p3.cross(p2p1);
  if (lessThan(d1 * d2, 0) && lessThan(d3 * d4, 0)) return true;
  if (almostEqual(d1, 0.0) && isPointOnSegment(s2.a, s1)) return true;
  if (almostEqual(d2, 0.0) && isPointOnSegment(s2.b, s1)) return true;
  if (almostEqual(d3, 0.0) && isPointOnSegment(s1.a, s2)) return true;
  if (almostEqual(d4, 0.0) && isPointOnSegment(s1.b, s2)) return true;
  return false;
 }

 /// @brief 線分の交点を返す
 Point getIntersection(const Segment& s1, const Segment& s2) {
  assert(isIntersecting(s1, s2));
  auto cross = [](Point p, Point q) { return p.x * q.y - p.y * q.x; };
  Point base = s2.b - s2.a;
  Real d1 = abs(cross(base, s1.a - s2.a));
  Real d2 = abs(cross(base, s1.b - s2.a));
  Real t = d1 / (d1 + d2);
  return s1.a + (s1.b - s1.a) * t;
 }

 /// @brief 点と線分の距離を返す
 Real distancePointToSegment(const Point& p, const Segment& s) {
  Point proj = projection(s.a, s.b, p);
  if (isPointOnSegment(proj, s))
   return (p - proj).abs();
  else
   return min((p - s.a).abs(), (p - s.b).abs());
 }

 /// @brief 線分と線分の距離を返す
 Real distanceSegmentToSegment(const Segment& s1, const Segment& s2) {
  if (isIntersecting(s1, s2)) return 0.0;
  return min({distancePointToSegment(s1.a, s2),
     distancePointToSegment(s1.b, s2),
     distancePointToSegment(s2.a, s1),
     distancePointToSegment(s2.b, s1)});
 }

 //-----------------------------------------------------------

 /// @brief 多角形の面積を返す
 Real getPolygonArea(const vector<Point>& points) {
  int n = points.size();
  Real area = 0.0;
  for (int i = 0; i < n; i++) {
   int j = (i + 1) % n;
   area += points[i].x * points[j].y;
   area -= points[i].y * points[j].x;
  }
  return abs(area) / 2.0;
 }

 /// @brief 多角形が凸か判定
 bool isConvex(const vector<Point>& points) {
  int n = points.size();
  bool has_positive = false, has_negative = false;
  for (int i = 0; i < n; i++) {
   int j = (i + 1) % n;
   int k = (i + 2) % n;
   Point a = points[j] - points[i];
   Point b = points[k] - points[j];
   Real cross_product = a.cross(b);
   if (greaterThan(cross_product, 0)) has_positive = true;
   if (lessThan(cross_product, 0)) has_negative = true;
  }
  return !(has_positive && has_negative);
 }

 /// @brief 点が凸多角形の辺上に存在するか判定
 bool isPointOnPolygon(const vector<Point>& polygon, const Point& p) {
  int n = polygon.size();
  for (int i = 0; i < n; i++) {
   Point a = polygon[i];
   Point b = polygon[(i + 1) % n];
   Segment s(a, b);
   if (isPointOnSegment(p, s)) return true;
  }
  return false;
 }

 /// @brief 点が多角形の内部に存在するか判定（辺上は含まない）
 bool isPointInsidePolygon(const vector<Point>& polygon, const Point& p) {
  int n = polygon.size();
  bool inPolygon = false;
  for (int i = 0; i < n; i++) {
   Point a = polygon[i];
   Point b = polygon[(i + 1) % n];
   if (greaterThan(a.y, b.y)) swap(a, b);
   if (lessThanOrEqual(a.y, p.y) && lessThan(p.y, b.y) && greaterThan((b - a).cross(p - a), 0)) inPolygon = !inPolygon;
  }
  return inPolygon;
 }

 //-----------------------------------------------------------

 /// @brief 凸包を求める
 vector<Point> convexHull(vector<Point>& points, bool include_collinear = false) {
  int n = points.size();
  if (n <= 1) return points;
  sort(points.begin(), points.end(), [](const Point& l, const Point& r) -> bool {
   if (almostEqual(l.y, r.y)) return lessThan(l.x, r.x);
   return lessThan(l.y, r.y);
  });
  if (n == 2) return points;
  vector<Point> upper = {points[0], points[1]}, lower = {points[0], points[1]};
  for (int i = 2; i < n; i++) {
   while (upper.size() >= 2 && ccw(upper.end()[-2], upper.end()[-1], points[i]) != CLOCKWISE) {
    if (ccw(upper.end()[-2], upper.end()[-1], points[i]) == ONLINE_FRONT && include_collinear) break;
    upper.pop_back();
   }
   upper.push_back(points[i]);
   while (lower.size() >= 2 && ccw(lower.end()[-2], lower.end()[-1], points[i]) != COUNTER_CLOCKWISE) {
    if (ccw(lower.end()[-2], lower.end()[-1], points[i]) == ONLINE_FRONT && include_collinear) break;
    lower.pop_back();
   }
   lower.push_back(points[i]);
  }
  reverse(upper.begin(), upper.end());
  upper.pop_back();
  lower.pop_back();
  lower.insert(lower.end(), upper.begin(), upper.end());
  return lower;
 }

 /// @brief 凸包の直径を求める
 Real convexHullDiameter(const vector<Point>& hull) {
  int n = hull.size();
  if (n == 1) return 0;
  int k = 1;
  Real max_dist = 0;
  for (int i = 0; i < n; i++) {
   while (true) {
    int j = (k + 1) % n;
    Point dist1 = hull[i] - hull[j], dist2 = hull[i] - hull[k];
    max_dist = max(max_dist, dist1.abs());
    max_dist = max(max_dist, dist2.abs());
    if (dist1.abs() > dist2.abs())
     k = j;
    else
     break;
   }
   Point dist = hull[i] - hull[k];
   max_dist = max(max_dist, dist.abs());
  }
  return max_dist;
 }

 /// @brief 凸包を直線で切断して左側を返す
 vector<Point> cutPolygon(const vector<Point>& g, const Line& l) {
  auto isLeft = [](const Point& p1, const Point& p2, const Point& p) -> bool { return (p2 - p1).cross(p - p1) > 0; };
  vector<Point> newPolygon;
  int n = g.size();
  for (int i = 0; i < n; i++) {
   const Point& cur = g[i];
   const Point& next = g[(i + 1) % n];
   if (isLeft(l.a, l.b, cur)) newPolygon.push_back(cur);
   if ((isLeft(l.a, l.b, cur) && !isLeft(l.a, l.b, next)) || (!isLeft(l.a, l.b, cur) && isLeft(l.a, l.b, next))) {
    Real A1 = (next - cur).cross(l.a - cur);
    Real A2 = (next - cur).cross(l.b - cur);
    Point intersection = l.a + (l.b - l.a) * (A1 / (A1 - A2));
    newPolygon.push_back(intersection);
   }
  }
  return newPolygon;
 }

 //-----------------------------------------------------------

 /// @brief 最近点対の距離を求める
 /// @note points は x 座標でソートされている必要がある
 Real closestPair(vector<Point>& points, int l, int r) {
  if (r - l <= 1) return numeric_limits<Real>::max();
  int mid = (l + r) >> 1;
  Real x = points[mid].x;
  Real d = min(closestPair(points, l, mid), closestPair(points, mid, r));
  auto iti = points.begin(), itl = iti + l, itm = iti + mid, itr = iti + r;
  inplace_merge(itl, itm, itr, [](const Point& lhs, const Point& rhs) -> bool {
   return lessThan(lhs.y, rhs.y);
  });
  vector<Point> nearLine;
  for (int i = l; i < r; i++) {
   if (greaterThanOrEqual(fabs(points[i].x - x), d)) continue;
   int sz = nearLine.size();
   for (int j = sz - 1; j >= 0; j--) {
    Point dv = points[i] - nearLine[j];
    if (dv.y >= d) break;
    d = min(d, dv.abs());
   }
   nearLine.push_back(points[i]);
  }
  return d;
 }

 //-----------------------------------------------------------

 /// @brief 線分の交差数を数える
 int countIntersections(vector<Segment> segments) {
  struct Event {
   Real x;
   int type;  // 0:horizontal start,1:vertical,2:horizontal end
   Real y1, y2;
   Event(Real x, int type, Real y1, Real y2) : x(x), type(type), y1(y1), y2(y2) {}
   bool operator<(const Event& other) const {
    if (x == other.x) return type < other.type;
    return x < other.x;
   }
  };
  vector<Event> events;
  sort(segments.begin(), segments.end(), [](const Segment& lhs, const Segment& rhs) -> bool {
   return lessThan(min(lhs.a.x, lhs.b.x), min(rhs.a.x, rhs.b.x));
  });
  for (const auto& seg : segments) {
   if (seg.a.y == seg.b.y) {
    // Horizontal segment
    Real y = seg.a.y;
    Real x1 = min(seg.a.x, seg.b.x);
    Real x2 = max(seg.a.x, seg.b.x);
    events.emplace_back(x1, 0, y, y);
    events.emplace_back(x2, 2, y, y);
   } else {
    // Vertical segment
    Real x = seg.a.x;
    Real y1 = min(seg.a.y, seg.b.y);
    Real y2 = max(seg.a.y, seg.b.y);
    events.emplace_back(x, 1, y1, y2);
   }
  }
  sort(events.begin(), events.end());
  set<Real> activeSegments;
  int intersectionCount = 0;
  for (const auto& event : events) {
   if (event.type == 0) {
    // Add horizontal segment to active set
    activeSegments.insert(event.y1);
   } else if (event.type == 2) {
    // Remove horizontal segment from active set
    activeSegments.erase(event.y1);
   } else if (event.type == 1) {
    // Count intersections with vertical segment
    auto lower = activeSegments.lower_bound(event.y1);
    auto upper = activeSegments.upper_bound(event.y2);
    intersectionCount += distance(lower, upper);
   }
  }
  return intersectionCount;
 }

 //-----------------------------------------------------------

 /// @brief 2つの円の交点の個数を返す
 int countCirclesIntersection(const Circle& c1, const Circle& c2) {
  Real d =
   sqrt((c1.center.x - c2.center.x) * (c1.center.x - c2.center.x) +
     (c1.center.y - c2.center.y) * (c1.center.y - c2.center.y));
  Real r1 = c1.r, r2 = c2.r;
  if (greaterThan(d, r1 + r2))
   return 4;
  else if (almostEqual(d, r1 + r2))
   return 3;
  else if (greaterThan(d, fabs(r1 - r2)))
   return 2;
  else if (almostEqual(d, fabs(r1 - r2)))
   return 1;
  else
   return 0;
 }

 /// @brief 内接円を求める
 Circle getInCircle(const Point& A, const Point& B, const Point& C) {
  Real a = (B - C).abs();
  Real b = (A - C).abs();
  Real c = (A - B).abs();
  Real s = (a + b + c) / 2;
  Real area = sqrt(s * (s - a) * (s - b) * (s - c));
  Real r = area / s;
  Real cx = (a * A.x + b * B.x + c * C.x) / (a + b + c);
  Real cy = (a * A.y + b * B.y + c * C.y) / (a + b + c);
  return Circle{Point(cx, cy), r};
 }

 /// @brief 外接円を求める
 Circle getCircumCircle(const Point& A, const Point& B, const Point& C) {
  Real D = 2 * (A.x * (B.y - C.y) + B.x * (C.y - A.y) + C.x * (A.y - B.y));
  Real Ux = ((A.x * A.x + A.y * A.y) * (B.y - C.y) + (B.x * B.x + B.y * B.y) * (C.y - A.y) + (C.x * C.x + C.y * C.y) * (A.y - B.y)) / D;
  Real Uy = ((A.x * A.x + A.y * A.y) * (C.x - B.x) + (B.x * B.x + B.y * B.y) * (A.x - C.x) + (C.x * C.x + C.y * C.y) * (B.x - A.x)) / D;
  Point center(Ux, Uy);
  Real radius = (center - A).abs();
  return Circle{center, radius};
 }

 /// @brief 円と直線の交点を求める
 vector<Point> getCircleLineIntersection(const Circle& c, Point p1, Point p2) {
  Real cx = c.center.x, cy = c.center.y, r = c.r;
  Real dx = p2.x - p1.x;
  Real dy = p2.y - p1.y;
  Real a = dx * dx + dy * dy;
  Real b = 2 * (dx * (p1.x - cx) + dy * (p1.y - cy));
  Real c_const = (p1.x - cx) * (p1.x - cx) + (p1.y - cy) * (p1.y - cy) - r * r;
  Real discriminant = b * b - 4 * a * c_const;
  vector<Point> intersections;
  if (almostEqual(discriminant, 0)) {
   Real t = -b / (2 * a);
   Real ix = p1.x + t * dx;
   Real iy = p1.y + t * dy;
   intersections.emplace_back(ix, iy);
   intersections.emplace_back(ix, iy);
  } else if (discriminant > 0) {
   Real sqrt_discriminant = sqrt(discriminant);
   Real t1 = (-b + sqrt_discriminant) / (2 * a);
   Real t2 = (-b - sqrt_discriminant) / (2 * a);
   Real ix1 = p1.x + t1 * dx;
   Real iy1 = p1.y + t1 * dy;
   Real ix2 = p1.x + t2 * dx;
   Real iy2 = p1.y + t2 * dy;
   intersections.emplace_back(ix1, iy1);
   intersections.emplace_back(ix2, iy2);
  }
  if (almostEqual(intersections[0].x, intersections[1].x)) {
   if (greaterThan(intersections[0].y, intersections[1].y)) swap(intersections[0], intersections[1]);
  } else if (greaterThan(intersections[0].x, intersections[1].x)) {
   swap(intersections[0], intersections[1]);
  }
  return intersections;
 }

 /// @brief 2つの円の交点を求める
 vector<Point> getCirclesIntersect(const Circle& c1, const Circle& c2) {
  Real x1 = c1.center.x, y1 = c1.center.y, r1 = c1.r;
  Real x2 = c2.center.x, y2 = c2.center.y, r2 = c2.r;
  Real d = sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
  if (d > r1 + r2 || d < abs(r1 - r2)) return {};  // No intersection
  Real a = (r1 * r1 - r2 * r2 + d * d) / (2 * d);
  Real h = sqrt(r1 * r1 - a * a);
  Real x0 = x1 + a * (x2 - x1) / d;
  Real y0 = y1 + a * (y2 - y1) / d;
  Real rx = -(y2 - y1) * (h / d);
  Real ry = (x2 - x1) * (h / d);
  Point p1(x0 + rx, y0 + ry);
  Point p2(x0 - rx, y0 - ry);
  vector<Point> intersections;
  intersections.push_back(p1);
  intersections.push_back(p2);
  if (almostEqual(intersections[0].x, intersections[1].x)) {
   if (greaterThan(intersections[0].y, intersections[1].y)) swap(intersections[0], intersections[1]);
  } else if (greaterThan(intersections[0].x, intersections[1].x)) {
   swap(intersections[0], intersections[1]);
  }
  return intersections;
 }

 /// @brief 点から引ける円の接線の接点を求める
 vector<Point> getTangentLinesFromPoint(const Circle& c, const Point& p) {
  Real cx = c.center.x, cy = c.center.y, r = c.r;
  Real px = p.x, py = p.y;
  Real dx = px - cx;
  Real dy = py - cy;
  Real d = (p - c.center).abs();
  if (lessThan(d, r))
   return {};  // No tangents if the point is inside the circle
  else if (almostEqual(d, r))
   return {p};
  Real a = r * r / d;
  Real h = sqrt(r * r - a * a);
  Real cx1 = cx + a * dx / d;
  Real cy1 = cy + a * dy / d;
  vector<Point> tangents;
  tangents.emplace_back(cx1 + h * dy / d, cy1 - h * dx / d);
  tangents.emplace_back(cx1 - h * dy / d, cy1 + h * dx / d);
  if (almostEqual(tangents[0].x, tangents[1].x)) {
   if (greaterThan(tangents[0].y, tangents[1].y)) swap(tangents[0], tangents[1]);
  } else if (greaterThan(tangents[0].x, tangents[1].x)) {
   swap(tangents[0], tangents[1]);
  }
  return tangents;
 }

 /// @brief 2つの円の共通接線を求める
 vector<Segment> getCommonTangentsLine(const Circle& c1, const Circle& c2) {
  Real x1 = c1.center.x, y1 = c1.center.y, r1 = c1.r;
  Real x2 = c2.center.x, y2 = c2.center.y, r2 = c2.r;
  Real dx = x2 - x1;
  Real dy = y2 - y1;
  Real d = sqrt(dx * dx + dy * dy);
  vector<Segment> tangents;
  // Coincident circles(infinite tangents)
  if (almostEqual(d, 0) && almostEqual(r1, r2)) return tangents;
  // External tangents
  if (greaterThanOrEqual(d, r1 + r2)) {
   Real a = atan2(dy, dx);
   for (int sign : {-1, 1}) {
    Real theta = acos((r1 + r2) / d);
    Real cx1 = x1 + r1 * cos(a + sign * theta);
    Real cy1 = y1 + r1 * sin(a + sign * theta);
    Real cx2 = x2 + r2 * cos(a + sign * theta);
    Real cy2 = y2 + r2 * sin(a + sign * theta);
    tangents.emplace_back(Segment{Point(cx1, cy1), Point(cx2, cy2)});
    if (almostEqual(d, r1 + r2)) break;
   }
  }
  // Internal tangents
  if (greaterThanOrEqual(d, fabs(r1 - r2))) {
   Real a = atan2(dy, dx);
   for (int sign : {-1, 1}) {
    Real theta = acos((r1 - r2) / d);
    Real cx1 = x1 + r1 * cos(a + sign * theta);
    Real cy1 = y1 + r1 * sin(a + sign * theta);
    Real cx2 = x2 - r2 * cos(a + sign * theta);
    Real cy2 = y2 - r2 * sin(a + sign * theta);
    tangents.emplace_back(Segment{Point(cx1, cy1), Point(cx2, cy2)});
    if (almostEqual(d, fabs(r1 - r2))) break;
   }
  }
  sort(tangents.begin(), tangents.end(), [&](const Segment& s1, const Segment& s2) {
   if (almostEqual(s1.a.x, s2.a.x))
    return lessThan(s1.a.y, s2.a.y);
   else
    return lessThan(s1.a.x, s2.a.x);
  });
  return tangents;
 }
}
// --- End of include: ./../../akakoi_lib/geometry/geometry.cpp ---

using namespace Geometry;

void solve() {
  int n; cin >> n;
  vector<Segment> S(n);
  rep(i, n) {
    int x1, y1, x2, y2; cin >> x1 >> y1 >> x2 >> y2;
    S[i] = Segment(Point(x1, y1), Point(x2, y2));
  }
  cout << countIntersections(S) << endl;
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout << fixed << setprecision(10);
  solve();
  return 0;
}
accuracy: 1
time_ms: 70
memory_kb: 32300
final_rank: 18

code_snippet: #include <bits/stdc++.h>
using namespace std;
#if __has_include(<atcoder/all>)
#include <atcoder/all>
using namespace atcoder;
#endif
#ifndef ONLINE_JUDGE
#define _GLIBCXX_DEBUG
#include <iostream>
template <typename T, typename U>
ostream& operator<<(ostream& os, const pair<T, U>& p) {return os<<'(' <<p.first<<", "<<p.second<<')';}
template <typename T>
ostream& operator<<(ostream& os, const vector<T>& v) {os<<'[';for(auto it=v.begin();it!=v.end();++it){os<<*it; if(next(it)!=v.end()){os<<", ";}}return os<<']';}
template <typename T>
ostream& operator<<(ostream& os, const vector<vector<T>>& vv) {os<<"[\n";for(auto it=vv.begin();it!=vv.end();++it){os<<"  "<<*it;if(next(it)!=vv.end()){os<<",\n";}else{os<<"\n";}}return os<<"]";}
#define dump(x) cerr << #x << " = " << (x) << '\n'
#else
#define dump(x) (void)0
#endif
using ll = long long;
using ld = long double;
using P = pair<ll,ll>;
template<class T> using pq = priority_queue<T>;
template<class T> using pq_g = priority_queue<T, vector<T>, greater<T>>;
#define out(x) cout<<x<<'\n'
#define all(v) (v).begin(),(v).end()
#define rall(v) (v).rbegin(),(v).rend()
#define OVERLOAD_REP(_1,_2,_3,name,...) name
#define REP1(i,n) for (auto i = std::decay_t<decltype(n)>{}; (i) < (n); ++(i))
#define REP2(i, l, r) for (auto i = (l); (i) < (r); ++(i))
#define rep(...) OVERLOAD_REP(__VA_ARGS__, REP2, REP1)(__VA_ARGS__)
template<class T> inline bool chmin(T& a, T b) {if(a > b){a = b; return true;} else {return false;}};
template<class T> inline bool chmax(T& a, T b) {if(a < b){a = b; return true;} else {return false;}};
const ll INF=(1LL<<60);
const ll mod=998244353;
using Graph = vector<vector<ll>>;
using Network = vector<vector<pair<ll,ll>>>;
using Grid = vector<string>;
const int dx[4] = {1, 0, -1, 0};
const int dy[4] = {0, 1, 0, -1};
const int dx2[8] = {1, 1,  1, 0,  0, -1, -1, -1};
const int dy2[8] = {1, 0, -1, 1, -1,  1,  0, -1};

// #include "../geo.hpp"

#pragma once

using D = long double;
const D EPS = 1e-12L;
const D PI = acosl(-1.0L);
using P2 = complex<D>;
struct L2{P2 a, b;};
struct S2{P2 a, b;};
using G2 = vector<P2>;

int sgn(D x){return (x>EPS)-(x<-EPS);}
int cmp(D a, D b){return sgn(a-b);}
bool eq(D a, D b){return cmp(a, b)==0;}
bool lt(D a, D b){return cmp(a, b)<0;}
bool le(D a, D b){return cmp(a, b)<=0;}
bool gt(D a, D b){return cmp(a, b)>0;}
bool ge(D a, D b){return cmp(a, b)>=0;}
bool eqP2(P2 a, P2 b){return eq(real(a), real(b)) && eq(imag(a), imag(b));}
bool ltP2(P2 a, P2 b) {
    return lt(real(a), real(b)) || (eq(real(a), real(b)) && lt(imag(a), imag(b)));
}

D dot(P2 a, P2 b) {return real(conj(a)*b);}
D cross(P2 a, P2 b) {return imag(conj(a)*b);}
int ccw(P2 a, P2 b, P2 c) {
    b-=a; c-=a;
    auto cr=cross(b, c), dt=dot(b, c);
    if (cr > EPS) return +1;       // counter clockwise
    if (cr < -EPS) return -1;      // clockwise
    if (dt < -EPS) return +2;         // c--a--b
    if (lt(norm(b), norm(c))) return -2; // a--b--c
    return 0;                  // a--c--b
}
int turn(P2 a, P2 b, P2 c) { return sgn(cross(b - a, c - a)); }

P2 rot(P2 a, D th) { return a*polar<D>(1, th); }
P2 rot90(P2 a) { return P2(-imag(a), real(a)); }
bool ltP2Arg(P2 a, P2 b) {
    auto up = [](P2 p) { return (imag(p) > 0 || (eq(imag(p), 0) && ge(real(p), 0))); };
    if (up(a) != up(b)) return up(a);
    if (!eq(cross(a, b), 0)) return cross(a, b) > 0;
    return lt(norm(a), norm(b));
}

inline void rd(P2& p) {D x, y; cin>>x>>y; p = P2(x, y);}
#define setp(n) cout<<setprecision(n)<<fixed
inline void pr(const P2& p) {setp(12); cout<<real(p)<<' '<<imag(p)<<'\n';}

// ----------------------------------------------------------------------------------

P2 proj(L2 l, P2 p) { P2 a=p-l.a, b=l.b-l.a; return l.a+b*dot(a, b)/norm(b);}
P2 refl(L2 l, P2 p) { return proj(l, p)*2.0L - p; }
bool isParallel(L2 l, L2 m){ return eq(cross(l.a-l.b, m.a-m.b), 0); }
bool isPerp(L2 l, L2 m){ return eq(dot(l.a-l.b, m.a-m.b), 0); }

bool isLL(L2 l, L2 m){ return !eq(cross(l.a-l.b, m.a-m.b), 0); }
bool isLS(L2 l, S2 s){ return turn(l.a, l.b, s.a)*turn(l.a, l.b, s.b)<=0; }
bool isSS(S2 s, S2 t) {
    return
    ccw(s.a,s.b,t.a)*ccw(s.a,s.b,t.b) <= 0 &&
    ccw(t.a,t.b,s.a)*ccw(t.a,t.b,s.b) <= 0;
}

P2 cpLL(L2 l, L2 m) {
    P2 a=l.b-l.a, b=m.b-m.a;
    D d=cross(a, b);
    if (eq(d, 0)) return P2(INF, INF); // parallel
    return l.a + a*cross(m.b-l.a,b)/d;
}

D distLP(L2 l, P2 p) { return abs(cross(l.b-l.a, p-l.a))/abs(l.b-l.a); }
D distSP(S2 s, P2 p) {
    P2 a=s.a, b=s.b;
    if (lt(dot(b-a, p-a), 0)) return abs(p-a);
    if (lt(dot(a-b, p-b), 0)) return abs(p-b);
    return distLP({a,b}, p);
}
D distSS(S2 s, S2 t) {
    if (isSS(s, t)) return 0;
    return min({distSP(s, t.a), distSP(s, t.b), distSP(t, s.a), distSP(t, s.b)});
}

D area(G2 g) {
    D s=0;
    int n=g.size();
    rep(i, n) s+=cross(g[i], g[(i+1)%n]);
    return s/2.0L;
}

bool isConvex(G2 g) {
    int n=g.size();
    if (n < 3) return false;
    int dir = 0;
    rep(i,n){
        int s = turn(g[i], g[(i+1)%n], g[(i+2)%n]);
        if (s == 0) return false; // -> continue : allows three points on a line
        if (dir == 0) dir = s;
        else if (dir*s < 0) return false;
    }
    return true;
}

int inG(G2 g, P2 p) {
    bool in=false;
    int n=g.size();
    rep(i, n) {
        P2 a=g[i], b=g[(i+1)%n];
        if (ccw(a, b, p) == 0) return 2; // on boundary
        if (a.imag() > b.imag()) swap(a, b);
        if (le(a.imag(), p.imag()) && lt(p.imag(), b.imag()) && turn(a, b, p) > 0) in=!in;
    }
    return in ? 1 : 0; // inside : outside
}

G2 hull(G2 g) {
    sort(all(g), ltP2);
    g.erase(unique(all(g), eqP2), g.end());
    if (g.size()<=1) return g;
    G2 lo, up;
    for (auto &p:g) {
        while (lo.size()>=2 && turn(lo[lo.size()-2], lo.back(), p)<=0) lo.pop_back(); //-> turn()<0 : allow three points on a line
        lo.push_back(p);
    }
    reverse(all(g));
    for (auto &p:g) {
        while (up.size()>=2 && turn(up[up.size()-2], up.back(), p)<=0) up.pop_back(); // -> turn()<0 : allow three points on a line
        up.push_back(p);
    }
    lo.pop_back(); up.pop_back();
    lo.insert(lo.end(), all(up));
    return lo;
}

pair<P2, P2> diameter(const G2& h) {
    int n=h.size();
    if(n==0) return {P2(0,0), P2(0,0)};
    if(n==1) return {h[0], h[0]};
    auto area2=[&](int i, int j, int k) {return abs(cross(h[j]-h[i], h[k]-h[i]));};
    D maxd=0;
    pair<P2, P2> res={h[0], h[0]};
    int j=1;
    rep(i, n) {
        int ni=(i+1)%n;
        while (gt(area2(i, ni, (j+1)%n), area2(i, ni, j))) j=(j+1)%n;
        if (gt(abs(h[i]-h[j]), maxd)) maxd=abs(h[i]-h[j]), res={h[i], h[j]};
        if (gt(abs(h[ni]-h[j]), maxd)) maxd=abs(h[ni]-h[j]), res={h[ni], h[j]};
    }
    return res;
}

// int inConvex(G2 h, P2 p) {
//     int n=h.size();
//     if (n==0) return 0;
//     if (n==1) return eqP2(h[0], p) ? 2 : 0;
//     if (n==2) return ccw(h[0], h[1], p)==0 && le(abs(h[0]-p)+abs(h[1]-p), abs(h[0]-h[1])) ? 2 : 0;
//     int left=1, right=n-1;
//     while (right-left>1) {
//         int mid=(left+right)/2;
//         if (turn(h[0], h[mid], p)<0) right=mid;
//         else left=mid;
//     }
//     if (turn(h[0], h[left], p)<0) return 0;
//     if (turn(h[left], h[right%n], p)<0) return 0;
//     if (turn(h[right%n], h[0], p)<0) return 0;
//     if (turn(h[0], h[left], p)==0 || turn(h[left], h[right%n], p)==0 || turn(h[right%n], h[0], p)==0) return 2;
//     return 1;
// }

G2 cutConvex(G2 h, L2 l) {
    int n=h.size();
    G2 res;
    if (n==0) return res;
    auto inside=[&](P2 p){ return turn(l.a, l.b, p) >= 0; };
    rep(i, n) {
        P2 a=h[i], b=h[(i+1)%n];
        bool ina=inside(a), inb=inside(b);
        if (ina&&inb) res.push_back(b);
        else if (ina&&!inb) {
            res.push_back(proj({a,b}, l.a));
        }
        else if (!ina&&inb) {
            res.push_back(proj({a,b}, l.a));
            res.push_back(b);
        }
    }
    return res;
}


pair<P2, P2> closestPair(G2 g) {
    auto ps = g;
    int n=ps.size();
    if (n < 2) return {P2(0,0), P2(0,0)};
    sort(all(ps), ltP2);
    D mind = norm(ps[0]-ps[1]);
    pair<P2, P2> res = {ps[0], ps[1]};
    set<pair<D,int>> box;
    int j=0;
    rep(i, n) {
        D xi=real(ps[i]), yi=imag(ps[i]);
        D rad = sqrtl(mind);
        while (j<i && gt(xi - real(ps[j]), rad)) {
            box.erase({imag(ps[j]), j});
            j++;
        }
        auto it = box.lower_bound({yi - rad, -1});
        for (; it != box.end() && le(it->first, yi + rad); ++it) {
            int k = it->second;
            D d = norm(ps[i]-ps[k]);
            if (lt(d, mind)) mind=d, res={ps[i], ps[k]}, rad = sqrtl(mind);
        }
        box.insert({yi, i});
    }
    return res;
}


struct C2 { P2 o; D r; };

C2 makeC2(P2 a, P2 b) {
    return C2{(a+b)/D(2), abs(a-b)/D(2)};
}
C2 makeC2(P2 a, P2 b, P2 c) {
    P2 B=b-a, C=c-a;
    D d=2*cross(B, C);
    if (eq(d, 0)) {
        D ab=norm(B), bc=norm(b-c), ca=norm(c-a);
        if (le(ab, bc) && le(ab, ca)) return makeC2(a, b);
        if (le(bc, ca)) return makeC2(b, c);
        return makeC2(c, a);
    }
    P2 o=a+(rot90(B)*norm(C)-rot90(C)*norm(B))/d;
    return C2{o, abs(o-a)};
}

C2 incircle(P2 a, P2 b, P2 c) {
    D ab=abs(b-a), bc=abs(c-b), ca=abs(a-c);
    P2 o=(a*bc+b*ca+c*ab)/(ab+bc+ca);
    D r=abs(cross(b-a, o-a))/abs(b-a);
    return C2{o, r};
}

vector<P2> cpCL(L2 l, C2 c) {
    vector<P2> res;
    P2 a=l.a-c.o, d=l.b-l.a;
    D A=norm(d), B=2*dot(a, d), C=norm(a)-c.r*c.r;
    D Dlt=B*B-4*A*C;
    if (lt(Dlt, 0)) return res;
    D s = le(Dlt, 0) ? 0 : sqrtl(max<D>(0, Dlt));
    D t1 = (-B - s)/(2*A), t2 = (-B + s)/(2*A);
    res.push_back(c.o + a + d*t1);
    if (gt(Dlt, 0)) res.push_back(c.o + a + d*t2);
    return res;
}

vector<P2> cpCC(C2 c1, C2 c2) {
    vector<P2> res;
    P2 d=c2.o-c1.o;
    D L=abs(d);
    if (eq(L, 0)) return res;
    D a=(c1.r*c1.r-c2.r*c2.r+L*L)/(2*L), h2=c1.r*c1.r-a*a;
    if (lt(h2, 0)) return res;
    P2 m=c1.o+d*(a/L), n=rot90(d)*( (lt(h2, 0) ? 0 : sqrtl(max<D>(0, h2))/L) );
    res.push_back(m-n);
    if (gt(h2, 0)) res.push_back(m+n);
    return res;
}

D isaCC(C2 c1, C2 c2) {
    D d=abs(c1.o-c2.o), r1=c1.r, r2=c2.r;
    if (ge(d, r1+r2)) return 0;
    if (le(d, abs(r1-r2))) {
        D r=min(r1, r2);
        return PI*r*r;
    }
    auto f = [&] (D z) { return max<D>(-1, min<D>(1, z)); };
    D a = 2*acosl(f((d*d+r1*r1-r2*r2)/(2*d*r1)));
    D b = 2*acosl(f((d*d+r2*r2-r1*r1)/(2*d*r2)));
    return 0.5L*(r1*r1*(a-sinl(a)) + r2*r2*(b-sinl(b)));
}

vector<L2> tangCP(C2 c, P2 p) {
    vector<L2> res;
    P2 v = p - c.o;
    D d2 = norm(v), r2 = c.r*c.r;
    if (lt(d2, r2)) return res;
    if (eq(d2, r2)) {
        res.push_back({c.o+v*(r2/d2), p});
        return res;
    }
    D h = c.r*sqrtl(max<D>(0, d2 - r2));
    P2 n1 = (v*r2 - rot90(v)*h)/d2;
    P2 n2 = (v*r2 + rot90(v)*h)/d2;
    res.push_back({c.o+n1, p});
    res.push_back({c.o+n2, p});
    return res;
}

vector<L2> tangCC(C2 c1, C2 c2) {
    vector<L2> res;
    P2 d = c2.o-c1.o;
    D L=abs(d);
    if (eq(L, 0)) return res;
    P2 e = d/L;
    auto add = [&] (int s) {
        D c=(s*c2.r - c1.r)/L;
        if (gt(c*c, 1)) return;
        D s2 = max<D>(0, 1 - c*c);
        if (eq(s2, 0)) {
            P2 n = e*c;
            res.push_back({c1.o-n*c1.r, c2.o-n*c2.r});
        } else {
            D s = sqrtl(s2);
            P2 n1 = e*c + rot90(e)*s;
            P2 n2 = e*c - rot90(e)*s;
            res.push_back({c1.o-n1*c1.r, c2.o-n1*c2.r});
            res.push_back({c1.o-n2*c1.r, c2.o-n2*c2.r});
        }
    };
    add(+1); // external
    add(-1); // internal
    return res;
}

C2 mec(G2 ps) {
    auto inC2=[&](C2 c, P2 p){ return le(abs(c.o - p), c.r); };
    mt19937_64 rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count());
    shuffle(all(ps), rng);
    int n=ps.size();
    if(n==0) return C2{P2(0,0), 0};
    C2 c{ps[0], 0};
    rep(i, n) {
        if (inC2(c, ps[i])) continue;
        c={ps[i], 0};
        rep(j, i) {
            if (inC2(c, ps[j])) continue;
            c=makeC2(ps[i], ps[j]);
            rep(k, j) {
                if (inC2(c, ps[k])) continue;
                c=makeC2(ps[i], ps[j], ps[k]);
            }
        }
    }
    return c;
}

vector<P2> cpSegs(vector<S2> ss) {
    struct E { D x; int t; D y, y1, y2; }; // t: 0=add(H), 1=query(V), 2=remove(H)
    vector<E> es; es.reserve(ss.size()*2);

    for(auto s: ss) {
        if (eq(s.a.imag(), s.b.imag())) {
            if (gt(s.a.real(), s.b.real())) swap(s.a, s.b);
            es.push_back({s.a.real(), 0, s.a.imag(), 0, 0});
            es.push_back({s.b.real(), 2, s.a.imag(), 0, 0});
        } else {
            if (gt(s.a.imag(), s.b.imag())) swap(s.a, s.b);
            es.push_back({s.a.real(), 1, 0, s.a.imag(), s.b.imag()});
        }
    }

    sort(all(es), [](E a, E b) {
        if (!eq(a.x, b.x)) return lt(a.x, b.x);
        return a.t < b.t;
    });

    multiset<D> active;
    vector<P2> res; res.reserve(ss.size());
    for (auto e : es) {
        if (e.t == 0) { // add
            active.insert(e.y);
        } else if (e.t == 2) { // remove
            auto it = active.find(e.y);
            if (it != active.end()) active.erase(it);
        } else { // query
            for (auto it = active.lower_bound(e.y1); it != active.end() && le(*it, e.y2); ++it) {
                res.push_back(P2(e.x, *it));
            }
        }
    }

    sort(all(res), ltP2);
    res.erase(unique(all(res), eqP2), res.end());
    return res;
}



// https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/1/CGL_1_A
void Projection() {
    P2 a, b; rd(a); rd(b);
    L2 l = {a, b};
    ll q;cin>>q;
    while(q--) {
        P2 p; rd(p);
        pr(proj(l, p));
    }
}

// https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/1/CGL_1_B
void Reflection() {
    P2 a, b; rd(a); rd(b);
    L2 l = {a, b};
    ll q;cin>>q;
    while(q--) {
        P2 p; rd(p);
        pr(refl(l, p));
    }
}

// https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/1/CGL_1_C
void CounterClockwise() {
    P2 p0, p1;
    rd(p0); rd(p1);
    ll q; cin>>q;
    while(q--) {
        P2 p; rd(p);
        int res = ccw(p0, p1, p);
        if (res == +1) out("COUNTER_CLOCKWISE");
        else if (res == -1) out("CLOCKWISE");
        else if (res == +2) out("ONLINE_BACK");
        else if (res == -2) out("ONLINE_FRONT");
        else out("ON_SEGMENT");
    }
}

// https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/1/CGL_2_A
void ParallelOrthogonal() {
    ll q;cin>>q;
    while(q--) {
        P2 p1, p2, p3, p4;
        rd(p1); rd(p2); rd(p3); rd(p4);
        if (isParallel({p1, p2}, {p3, p4})) out(2);
        else if(isPerp({p1, p2}, {p3, p4})) out(1);
        else out(0);
    }
}

// https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/2/CGL_2_B
void IntersectionSS() {
    ll q;cin>>q;
    while(q--) {
        P2 p1, p2, p3, p4;
        rd(p1); rd(p2); rd(p3); rd(p4);
        S2 s1 = {p1, p2}, s2 = {p3, p4};
        out(isSS(s1, s2));
    }
}

// https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/2/CGL_2_C
void CrossPointSS() {
    ll q;cin>>q;
    while(q--) {
        P2 p1, p2, p3, p4;
        rd(p1); rd(p2); rd(p3); rd(p4);
        L2 s1 = {p1, p2}, s2 = {p3, p4};
        pr(cpLL(s1, s2));
    }
}

// https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/2/CGL_2_D
void DistanceSS() {
    ll q;cin>>q;
    while(q--) {
        P2 p1, p2, p3, p4;
        rd(p1); rd(p2); rd(p3); rd(p4);
        S2 s1 = {p1, p2}, s2 = {p3, p4};
        setp(12);
        out(distSS(s1, s2));
    }
}

// https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/3/CGL_3_A
void Area() {
    ll n;cin>>n;
    G2 g(n);
    rep(i, n) rd(g[i]);
    setp(12);
    out(area(g));
}

// https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/3/CGL_3_B
void IsConvex() {
    ll n;cin>>n;
    G2 g(n);
    rep(i, n) rd(g[i]);
    out(isConvex(g));
}

// https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/3/CGL_3_C
void PolygonPointContainment() {
    ll n;cin>>n;
    G2 g(n);
    rep(i, n) rd(g[i]);
    ll q;cin>>q;
    while(q--) {
        P2 p; rd(p);
        out(inG(g, p));
    }
}

// https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/4/CGL_4_A
void ConvexHull() {
    ll n;cin>>n;
    G2 g(n);
    rep(i, n) rd(g[i]);
    G2 h = hull(g);
    out(h.size());
    rep(i, h.size()) pr(h[i]);
}

// https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/4/CGL_4_B
void DiameterOfConvexPolygon() {
    ll n;cin>>n;
    G2 g(n);
    rep(i, n) rd(g[i]);
    auto [p1, p2] = diameter(g);
    setp(12);
    out(abs(p1 - p2));
}

// https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/4/CGL_4_C
void ConvexCut() {
    ll n;cin>>n;
    G2 g(n);
    rep(i, n) rd(g[i]);
    ll q;cin>>q;
    while(q--) {
        P2 a, b; rd(a); rd(b);
        L2 l = {a, b};
        G2 h = cutConvex(g, l);
        setp(12);
        out(area(h));
    }
}

// https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/5/CGL_5_A
void ClosestPair() {
    ll n;cin>>n;
    G2 g(n);
    rep(i, n) rd(g[i]);
    auto [p1, p2] = closestPair(g);
    setp(12);
    out(abs(p1 - p2));
}

// https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/5/CGL_5_B
void MinimumEnclosingCircle() {
    ll n;cin>>n;
    G2 g(n);
    rep(i, n) rd(g[i]);
    auto [c, r] = mec(g);
    pr(c);
    setp(12);
    out(r);
}


// https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/6/CGL_6_A
void SegmentIntersections() {
    ll n;cin>>n;
    vector<S2> seg(n);
    rep(i, n) {
        P2 a, b; rd(a); rd(b);
        seg[i] = {a, b};
    }
    out(cpSegs(seg).size());
}


// // https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/7/CGL_7_A
void IntersectionOfCircles() {
    P2 o1, o2; D r1, r2;
    rd(o1); cin>>r1;
    rd(o2); cin>>r2;
    C2 c1={o1, r1}, c2={o2, r2};
    out(tangCC(c1, c2).size());
}

// // https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/7/CGL_7_B
void IncircleOfTriangle() {
    P2 a, b, c; rd(a); rd(b); rd(c);
    auto [ic, ir] = incircle(a, b, c);
    pr(ic);
    setp(12);
    out(ir);
}

// // https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/7/CGL_7_C
void CircumscribedCircleOfTriangle() {
    P2 a, b, c; rd(a); rd(b); rd(c);
    auto [cc, cr] = makeC2(a, b, c);
    pr(cc);
    setp(12);
    out(cr);
}

// // https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/7/CGL_7_D
void CrossPointsCL() {
    P2 c; D r;
    rd(c); cin>>r;
    ll q;cin>>q;
    while(q--) {
        P2 a, b; rd(a); rd(b);
        L2 l = {a, b};
        auto ps = cpCL(l, {c, r});
        sort(all(ps), ltP2);
        pr(ps[0]);
        pr(ps[(ps.size()-1)]);
    }
}

// // https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/7/CGL_7_E
void CrossPointsCC() {
    P2 o1, o2; D r1, r2;
    rd(o1); cin>>r1;
    rd(o2); cin>>r2;
    C2 c1={o1, r1}, c2={o2, r2};
    auto ps = cpCC(c1, c2);
    sort(all(ps), ltP2);
    pr(ps[0]);
    pr(ps[(ps.size()-1)]);
}

// // https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/7/CGL_7_F
void TangentToCircle() {
    P2 p, c; D r;
    rd(p);
    rd(c); cin>>r;
    C2 c1={c, r};
    auto ls = tangCP(c1, p);
    vector<P2> ps;
    for (auto l : ls) {
        ps.push_back(l.a);
    }
    sort(all(ps), ltP2);
    for (auto p : ps) pr(p);
}

// // https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/7/CGL_7_G
void CommonTangent() {
    P2 o1, o2; D r1, r2;
    rd(o1); cin>>r1;
    rd(o2); cin>>r2;
    C2 c1={o1, r1}, c2={o2, r2};
    auto ls = tangCC(c1, c2);
    vector<P2> ps;
    for (auto l : ls) {
        ps.push_back(l.a);
    }
    sort(all(ps), ltP2);
    for (auto p : ps) pr(p);
}

// // https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/7/CGL_7_H
// void IntersectionCP() {
//     ll n;cin>>n;
//     D r; cin>>r;
//     C2 c = {P2(0, 0), r};
//     G2 g(n);
//     rep(i, n) rd(g[i]);
//     out(isaCP(c, g));
// }

// // https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/7/CGL_7_I
void AreaOfIntersectionBetweenTwoCircles() {
    P2 o1, o2; D r1, r2;
    rd(o1); cin>>r1;
    rd(o2); cin>>r2;
    C2 c1={o1, r1}, c2={o2, r2};
    setp(12);
    out(isaCC(c1, c2));
}

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

    // Projection();
    // Reflection();
    // CounterClockwise();

    // ParallelOrthogonal();
    // IntersectionSS();
    // CrossPointSS();
    // DistanceSS();

    // Area();
    // IsConvex();
    // PolygonPointContainment();

    // ConvexHull();
    // DiameterOfConvexPolygon();
    // ConvexCut();

    // ClosestPair();
    // MinimumEnclosingCircle();

    SegmentIntersections();

    // IntersectionOfCircles();
    // IncircleOfTriangle();
    // CircumscribedCircleOfTriangle();
    // CrossPointsCL();
    // CrossPointsCC();
    // TangentToCircle();
    // CommonTangent();
    // IntersectionCP();
    // AreaOfIntersectionBetweenTwoCircles();
    return 0;
}
accuracy: 1
time_ms: 220
memory_kb: 71532
final_rank: 20

code_snippet: #include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <climits>
#include <unordered_map>
#include <queue>
#include <deque>
#include <math.h>
#include <limits.h>
#include <set>
#include <stack>
#include <map>
#include <bits/stdc++.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <cmath>
#define Lt Line<T>
#define Pt Point<T>
#define ll long long



//#define double long double
using namespace std;


const ll N=2e4+10,M=1e6+10,MOD=998244353;

typedef std::pair<ll,ll> pii;
typedef std::pair<ll,std::pair<ll,ll> > piii;


//ll n,m;

using ld = long double;
const ld PI = acos(-1);
const ld EPS = 1e-7;
const ld INF = numeric_limits<ld>::max();
#define cc(x) cout << fixed << setprecision(x);

ld fgcd(ld x, ld y) { // 实数域gcd
    return abs(y) < EPS ? abs(x) : fgcd(y, fmod(x, y));
}
template<class T, class S> bool equal(T x, S y) {
    return -EPS < x - y && x - y < EPS;
}
template<class T> int sign(T x) {
    if (-EPS < x && x < EPS) return 0;
    return x < 0 ? -1 : 1;
}



template<class T> struct Point { // 在C++17下使用 emplace_back 绑定可能会导致CE！
    T x, y;
    Point(T x_ = 0, T y_ = 0) : x(x_), y(y_) {} // 初始化
    template<class U> operator Point<U>() { // 自动类型匹配
        return Point<U>(U(x), U(y));
    }
    Point &operator+=(Point p) & { return x += p.x, y += p.y, *this; }
    Point &operator+=(T t) & { return x += t, y += t, *this; }
    Point &operator-=(Point p) & { return x -= p.x, y -= p.y, *this; }
    Point &operator-=(T t) & { return x -= t, y -= t, *this; }
    Point &operator*=(T t) & { return x *= t, y *= t, *this; }
    Point &operator/=(T t) & { return x /= t, y /= t, *this; }
    Point operator-() const { return Point(-x, -y); }
    friend Point operator+(Point a, Point b) { return a += b; }
    friend Point operator+(Point a, T b) { return a += b; }
    friend Point operator-(Point a, Point b) { return a -= b; }
    friend Point operator-(Point a, T b) { return a -= b; }
    friend Point operator*(Point a, T b) { return a *= b; }
    friend Point operator*(T a, Point b) { return b *= a; }
    friend Point operator/(Point a, T b) { return a /= b; }
    friend bool operator<(Point a, Point b) {
        return equal(a.x, b.x) ? a.y < b.y - EPS : a.x < b.x - EPS;
    }
    friend bool operator>(Point a, Point b) { return b < a; }
    friend bool operator==(Point a, Point b) { return !(a < b) && !(b < a); }
    friend bool operator!=(Point a, Point b) { return a < b || b < a; }
    friend auto &operator>>(istream &is, Point &p) {
        return is >> p.x >> p.y;
    }
    friend auto &operator<<(ostream &os, Point p) {
        return os << "(" << p.x << ", " << p.y << ")";
    }
};
template<class T> struct Line {
    Point<T> a, b;
    Line(Point<T> a_ = Point<T>(), Point<T> b_ = Point<T>()) : a(a_), b(b_) {}
    template<class U> operator Line<U>() { // 自动类型匹配
        return Line<U>(Point<U>(a), Point<U>(b));
    }
    friend auto &operator<<(ostream &os, Line l) {
        return os << "<" << l.a << ", " << l.b << ">";
    }
};

using Pd = Point<ld>;
using Ld = Line<ld>;

template<class T> T cross(Point<T> a, Point<T> b) { // 叉乘
    return a.x * b.y - a.y * b.x;
}
template<class T> T cross(Point<T> p1, Point<T> p2, Point<T> p0) { // 叉乘 (p1 - p0) x (p2 - p0);
    return cross(p1 - p0, p2 - p0);
}

template<class T> T dot(Point<T> a, Point<T> b) { // 点乘
    return a.x * b.x + a.y * b.y;
}
template<class T> T dot(Point<T> p1, Point<T> p2, Point<T> p0) { // 点乘 (p1 - p0) * (p2 - p0);
    return dot(p1 - p0, p2 - p0);
}

template <class T> ld dis(T x1, T y1, T x2, T y2) {
    ld val = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
    return sqrt(val);
}
template <class T> ld dis(Point<T> a, Point<T> b) {
    return dis(a.x, a.y, b.x, b.y);
}

template<class T> Point<T> rotate(Point<T> p1, Point<T> p2) { // 旋转
    Point<T> vec = p1 - p2;
    return {-vec.y, vec.x};
}

Point<ld> rotate(Point<ld> p, ld rad) {
    return {p.x * cos(rad) - p.y * sin(rad), p.x * sin(rad) + p.y * cos(rad)};
}

Point<ld> rotate(Point<ld> a, Point<ld> b, ld rad) {
    ld x = (a.x - b.x) * cos(rad) + (a.y - b.y) * sin(rad) + b.x;
    ld y = (b.x - a.x) * sin(rad) + (a.y - b.y) * cos(rad) + b.y;
    return {x, y};
}

template<class T> bool onLine(Point<T> a, Point<T> b, Point<T> c) {
    return sign(cross(b, a, c)) == 0;
}
template<class T> bool onLine(Point<T> p, Line<T> l) {
    return onLine(p, l.a, l.b);
}

template<class T> bool lineParallel(Line<T> p1, Line<T> p2) {
    return sign(cross(p1.a - p1.b, p2.a - p2.b)) == 0;
}
template<class T> bool lineVertical(Line<T> p1, Line<T> p2) {
    return sign(dot(p1.a - p1.b, p2.a - p2.b)) == 0;
}
template<class T> bool same(Line<T> l1, Line<T> l2) {
    return lineParallel(Line{l1.a, l2.b}, {l1.b, l2.a}) &&
           lineParallel(Line{l1.a, l2.a}, {l1.b, l2.b}) && lineParallel(l1, l2);
}

template<class T> ld disPointToLine(Point<T> p, Line<T> l) {
    ld ans = cross(p, l.a, l.b);
    return abs(ans) / dis(l.a, l.b); // 面积除以底边长
}

template<class T> bool pointOnSegment(Point<T> p, Line<T> l) { // 端点也算作在直线上
    return sign(cross(p, l.a, l.b)) == 0 && min(l.a.x, l.b.x) <= p.x && p.x <= max(l.a.x, l.b.x) &&
           min(l.a.y, l.b.y) <= p.y && p.y <= max(l.a.y, l.b.y);
}

template<class T> bool segmentIntersection(Line<T> l1, Line<T> l2) {
    auto [s1, e1] = l1;
    auto [s2, e2] = l2;
    auto A = max(s1.x, e1.x), AA = min(s1.x, e1.x);
    auto B = max(s1.y, e1.y), BB = min(s1.y, e1.y);
    auto C = max(s2.x, e2.x), CC = min(s2.x, e2.x);
    auto D = max(s2.y, e2.y), DD = min(s2.y, e2.y);
    return A >= CC && B >= DD && C >= AA && D >= BB &&
           sign(cross(s1, s2, e1) * cross(s1, e1, e2)) == 1 &&
           sign(cross(s2, s1, e2) * cross(s2, e2, e1)) == 1;
}//其中重叠、相交于端点均视为不相交。

Pd lineIntersection(Ld l1, Ld l2) {
    ld val = cross(l2.b - l2.a, l1.a - l2.a) / cross(l2.b - l2.a, l1.a - l1.b);
    return l1.a + (l1.b - l1.a) * val;
}

pair<Pd, ld> pointToLine(Pd p, Ld l) {
    Pd ans = lineIntersection({p, p + rotate(l.a, l.b)}, l);
    return {ans, dis(p, ans)};
}

pair<Pd, ld> pointToSegment(Pd p, Ld l) {
    if (sign(dot(p, l.b, l.a)) == -1) { // 特判到两端点的距离
        return {l.a, dis(p, l.a)};
    } else if (sign(dot(p, l.a, l.b)) == -1) {
        return {l.b, dis(p, l.b)};
    }
    return pointToLine(p, l);
}

ld DisSegToSeg(Ld l1,Ld l2)
{
    // if(lineParallel(l1,l2)) 
    // {
    //     auto [t1,ans1]=pointToSegment(l1.a,l2);
    //     return ans1;
    // }
    if(segmentIntersection(l1,l2)) return 0.0;
    auto [t1,ans1]=pointToSegment(l1.a,l2);
    auto [t2,ans2]=pointToSegment(l1.b,l2);
    auto [t3,ans3]=pointToSegment(l2.a,l1);
    auto [t4,ans4]=pointToSegment(l2.b,l1);
    //cout<<ans1<<' '<<ans2<<' '<<ans3<<' '<<ans4<<'\n';
    return min(min(ans1,ans2),min(ans3,ans4));
}

template<class T> ld area(vector<Point<T>> P) {
    int n = P.size();
    ld ans = 0;
    for (int i = 0; i < n; i++) {
        ans += cross(P[i], P[(i + 1) % n]);
    }
    return ans / 2.0;
}

template<class T> vector<Point<T>> staticConvexHull(vector<Point<T>> A, int flag = 1) {
    int n = A.size();
    if (n <= 2) { // 特判
        return A;
    }
    vector<Point<T>> ans(n * 2);
    sort(A.begin(), A.end());
    int now = -1;
    for (int i = 0; i < n; i++) { // 维护下凸包
        while (now > 0 && cross(A[i], ans[now], ans[now - 1]) < 0) {
            now--;
        }
        ans[++now] = A[i];
    }
    int pre = now;
    for (int i = n - 2; i >= 0; i--) { // 维护上凸包
        while (now > pre && cross(A[i], ans[now], ans[now - 1]) <= 0) {
            now--;
        }
        ans[++now] = A[i];
    }
    ans.resize(now);
    sort(ans.begin(),ans.end());
    ans.erase(unique(ans.begin(),ans.end()),ans.end());
    return ans;
}



template<class T> T sqr(T x) {
    return x * x;
}

template<class T> T disEx(Pt a1,Pt a2)
{
    return (a1.x-a2.x)*(a1.x-a2.x)+(a1.y-a2.y)*(a1.y-a2.y);
}

// 计算最小包围圆（最小圆覆盖）
// 输入：点集的迭代器范围 [left, right)，随机种子 seed
// 输出：pair<圆心, 半径平方>
template <class T>
std::pair<Point<T>, ld> min_ball(vector<Pt> A, int seed = 1333) {
    
    const int n = A.size();  // 点的数量

    assert(n >= 1);  // 至少需要1个点
    
    // 特殊情况处理：只有1个点
    if (n == 1) {
        return {A[0], ld(0)};  // 圆就是点本身，半径为0
    }

    // 随机数生成器
    std::mt19937 mt(seed);
    // 随机打乱点集顺序 - 这是保证O(n)期望时间复杂度的关键
    std::shuffle(A.begin(), A.end(), mt);

    vector<Pt> &ps=A;

    using circle = std::pair<Pt, ld>;  // 圆类型：圆心 + 半径平方

    // 通过三个点构造圆的lambda函数
    auto make_circle_3 = [](const Pt &a, const Pt &b, const Pt &c) -> circle {
        // 使用三角形外心公式计算圆心
        ld A = disEx(b , c),  // |BC|²
           B = disEx(c , a),  // |CA|²  
           C = disEx(a , b),  // |AB|²
           S = cross(b - a, c - a);  // 三角形面积的2倍
        
        // 外心坐标公式（重心坐标形式）
        Pt p = (A * (B + C - A) * a + B * (C + A - B) * b + C * (A + B - C) * c) / (4 * S * S);
        ld r2 = disEx(p , a);  // 半径的平方
        return {p, r2};
    };

    // 通过两个点构造圆的lambda函数（以两点为直径的圆）
    auto make_circle_2 = [](const Pt &a, const Pt &b) -> circle {
        Pt c = (a + b) / (ld)2;  // 圆心为两点中点
        ld r2 = disEx(a , c);  // 半径平方
        return {c, r2};
    };

    // 判断点是否在圆内的lambda函数
    auto in_circle = [](const Pt &a, const circle &c) -> bool {
        // 判断点到圆心的距离平方是否 <= 半径平方 + 容误差
        return disEx(a , c.first) <= c.second + EPS;
    };

    // 初始化：用前两个点构造初始圆
    circle c = make_circle_2(ps[0], ps[1]);

    // 主循环：逐个处理剩余的点
    for (int i = 2; i < n; ++i) {
        // 如果当前点不在当前圆内，需要更新圆
        if (!in_circle(ps[i], c)) {
            // MiniDiscWithPoint: 新圆必须包含当前点ps[i]
            c = make_circle_2(ps[0], ps[i]);  // 初始尝试：用第一个点和当前点构造圆
            
            // 检查前面的点是否都在新圆内
            for (int j = 1; j < i; ++j) {
                if (!in_circle(ps[j], c)) {
                    // MiniDiscWith2Points: 新圆必须包含ps[i]和ps[j]
                    c = make_circle_2(ps[i], ps[j]);  // 用当前两个点构造圆
                    
                    // 检查更前面的点
                    for (int k = 0; k < j; ++k) {
                        if (!in_circle(ps[k], c)) {
                            // 三个点确定唯一圆
                            c = make_circle_3(ps[i], ps[j], ps[k]);
                        }
                    }
                }
            }
        }
        // 如果当前点在圆内，直接跳过（概率O(1/k)，这是算法高效的关键）
    }
    return c;
}

tuple<int, Pd, Pd> circleIntersection(Pd p1, ld r1, Pd p2, ld r2) {
    ld x1 = p1.x, x2 = p2.x, y1 = p1.y, y2 = p2.y;
    ld d = dis(p1, p2);
    
    // 检查圆的位置关系
    if (sign(d) == 0) { // 同心圆
        if (sign(r1 - r2) == 0) return {4, {}, {}}; // 重合
        else return {0, {}, {}}; // 内含
    }
    
    if (sign(d - (r1 + r2)) == 1) { // 相离
        return {0, {}, {}};
    } else if (sign(abs(r1 - r2) - d) == 1) { // 内含
        return {0, {}, {}};
    }
    
    // 计算交点
    ld dx = x2 - x1, dy = y2 - y1;
    ld a = (r1*r1 - r2*r2 + d*d) / (2*d);
    ld h = sqrt(r1*r1 - a*a);
    
    // 中点
    ld xm = x1 + a * dx / d;
    ld ym = y1 + a * dy / d;
    
    // 垂直方向的偏移量
    ld xoff = -h * dy / d;
    ld yoff = h * dx / d;
    
    Pd ans1 = {xm + xoff, ym + yoff};
    Pd ans2 = {xm - xoff, ym - yoff};
    
    if (sign(dis(ans1, ans2)) == 0) { // 相切，一个交点
        return {2, ans1, ans1};
    } else { // 相交，两个交点
        return {3, ans1, ans2};
    }
}

template<class T> Lt midSegment(Lt l) {
    Pt mid = (l.a + l.b) / 2; // 线段中点
    return {mid, mid + rotate(l.a, l.b)};
}

tuple<int, Pd, ld> getCircle(Pd A, Pd B, Pd C) {
    if (onLine(A, B, C)) { // 特判三点共线
        return {0, {}, 0};
    }
    Ld l1 = midSegment(Line{A, B});
    Ld l2 = midSegment(Line{A, C});
    Pd O = lineIntersection(l1, l2);
    return {1, O, dis(A, O)};
}

pair<Pd,ld> getIncircle(Pd A,Pd B,Pd C)
{
    ld AB=dis(A,B);
    ld AC=dis(A,C);
    ld BC=dis(B,C);
    Pd ans((AB*C.x+AC*B.x+BC*A.x)/(AB+AC+BC),(AB*C.y+AC*B.y+BC*A.y)/(AB+AC+BC));
    ld ans1=cross(A,B,C)/(AB+AC+BC);
    return {ans,max(ans1,-ans1)};
}

Pd project(Pd p, Ld l) { // 投影
    Pd vec = l.b - l.a;
    ld r = dot(vec, p - l.a) / (vec.x * vec.x + vec.y * vec.y);
    return l.a + vec * r;
}

Point<ld> standardize(Point<ld> vec) { // 转换为单位向量
    return vec / sqrt(vec.x * vec.x + vec.y * vec.y);
}

tuple<int, Pd, Pd> lineCircleCross(Ld l, Pd o, ld r) {
    Pd P = project(o, l);
    ld d = dis(P, o), tmp = r * r - d * d;
    if (sign(tmp) == -1) {
        return {0, {}, {}};
    } else if (sign(tmp) == 0) {
        return {1, P, {}};
    }
    Pd vec = standardize(l.b - l.a) * sqrt(tmp);
    return {2, P + vec, P - vec};
}

Point<ld> getPoint(Point<ld> p, ld r, ld rad) {
    return {p.x + cos(rad) * r, p.y + sin(rad) * r};
}

pair<int, vector<Point<ld>>> tangent(Point<ld> p, Point<ld> A, ld r) {
    vector<Point<ld>> ans;
    ld d = dis(p, A);
    
    if (sign(d - r) < 0) {
        // 点在圆内，无切线
        return {0, {}};
    } else if (sign(d - r) == 0) {
        // 点在圆上，只有一条切线
        // 切点就是p本身
        ans.push_back(p);
        return {1, ans};
    } else {
        // 点在圆外，有两条切线
        Point<ld> u = A - p;
        
        // 使用圆心和半径计算
        // 计算圆心到切点的方向角
        ld alpha = atan2(u.y, u.x);
        ld beta = asin(r / d);
        
        Point<ld> t1_alt = getPoint(A, r, alpha + beta + M_PI_2);
        Point<ld> t2_alt = getPoint(A, r, alpha - beta - M_PI_2);
        
        ans.push_back(t1_alt);
        ans.push_back(t2_alt);
        
        return {2, ans};
    }
}

tuple<int, vector<Point<ld>>, vector<Point<ld>>> tangent(Point<ld> A, ld Ar, Point<ld> B, ld Br) {
    vector<Point<ld>> a, b; // 储存切点
    if (Ar < Br) {
        swap(Ar, Br);
        swap(A, B);
        swap(a, b);
    }
    int d = disEx(A, B), dif = Ar - Br, sum = Ar + Br;
    if (d < dif * dif) { // 内含，无
        return {0, {}, {}};
    }
    ld base = atan2(B.y - A.y, B.x - A.x);
    if (d == 0 && Ar == Br) { // 完全重合，无数条外公切线
        return {-1, {}, {}};
    }
    if (d == dif * dif) { // 内切，1条外公切线
        a.push_back(getPoint(A, Ar, base));
        b.push_back(getPoint(B, Br, base));
        return {1, a, b};
    }
    ld ang = acos(dif / sqrt(d));
    a.push_back(getPoint(A, Ar, base + ang)); // 保底2条外公切线
    a.push_back(getPoint(A, Ar, base - ang));
    b.push_back(getPoint(B, Br, base + ang));
    b.push_back(getPoint(B, Br, base - ang));
    if (d == sum * sum) { // 外切，多1条内公切线
        a.push_back(getPoint(A, Ar, base));
        b.push_back(getPoint(B, Br, base + PI));
    } else if (d > sum * sum) { // 相离，多2条内公切线
        ang = acos(sum / sqrt(d));
        a.push_back(getPoint(A, Ar, base + ang));
        a.push_back(getPoint(A, Ar, base - ang));
        b.push_back(getPoint(B, Br, base + ang + PI));
        b.push_back(getPoint(B, Br, base - ang + PI));
    }
    return {a.size(), a, b};
}

ld angle(ld a, ld b, ld c) { // 余弦定理
    ld val = acos((a * a + b * b - c * c) / (2.0 * a * b)); // 计算弧度
    return val;
}

ld circleIntersectionArea(Pd p1, ld r1, Pd p2, ld r2) {
    ld x1 = p1.x, x2 = p2.x, y1 = p1.y, y2 = p2.y, d = dis(p1, p2);
    if (sign(abs(r1 - r2) - d) >= 0) {
        return PI * min(r1 * r1, r2 * r2);
    } else if (sign(r1 + r2 - d) == -1) {
        return 0;
    }
    ld theta1 = angle(r1, dis(p1, p2), r2);
    ld area1 = r1 * r1 * (theta1 - sin(theta1 * 2) / 2);
    ld theta2 = angle(r2, dis(p1, p2), r1);
    ld area2 = r2 * r2 * (theta2 - sin(theta2 * 2) / 2);
    return area1 + area2;
}

template <class T> struct ManPoint
{
    Pt Now;
    int Type;
    Pt Ne;
    ManPoint (){};
    ManPoint (Pt A,Pt B)
    {
        Now=A; Ne=B;
        if(A.y==B.y) Type=((A.x<B.x)?2:3);
        else Type=((A.y<B.y)?1:4);
    }
    friend bool operator < (ManPoint A,ManPoint B)
    {
        if(A.Now.y==B.Now.y) return A.Type<B.Type;
        return A.Now.y<B.Now.y;
    }
    friend bool operator > (ManPoint A,ManPoint B) {return B<A;}
};

template <class T> ll ManhattanIn(vector<Line<T>> A)
{
    vector<ManPoint<T>> MP;
    for(auto [x,y]:A)
    {
        ManPoint x1(x,y),y1(y,x);
        MP.push_back(x1); MP.push_back(y1);
    }
    set<T> S;
    sort(MP.begin(),MP.end());
    ll ans=0;
    for(auto Mpo:MP)
    {
        if(Mpo.Type==1) S.insert(Mpo.Now.x);
        else if(Mpo.Type==2) 
        {
            auto LE=(lower_bound(S.begin(),S.end(),Mpo.Now.x));
            auto RI=(upper_bound(S.begin(),S.end(),Mpo.Ne.x));
            ans+=distance(LE,RI);
        }
        else if(Mpo.Type==4) S.erase(Mpo.Now.x);
    }
    return ans;
}



int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);

    int n; cin>>n;
    vector<Line<ll>> z(n);
    
    for(int i=0;i<n;i++)
    {
        Point<ll> a,b; cin>>a>>b;
        z[i]={a,b};
    }
    
    cout<<ManhattanIn(z)<<'\n';
    
    return 0;
}
accuracy: 1
time_ms: 460
memory_kb: 21784
final_rank: 19

code_snippet: #include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'


#define maxn 200010
int n,m,cnt,ans,Hash[maxn],tr[maxn];
struct Point{
    int x,y;
    bool operator <(Point p){
        if(x!=p.x)return x<p.x;
        return y<p.y;
    }
};Point p[maxn];
struct seg{
    int k,x,y,r;
    bool operator<(seg s){
        if(y==s.y)return k>s.k;
        return y<s.y;
    }
};seg s[maxn];

int find(int x){
    return lower_bound(Hash+1,Hash+1+m,x)-Hash;
}
void insert(int k,int l,int r,int t){
    if(!k){
        s[++cnt].x=find(l);
        s[cnt].r = find(r);
        s[cnt].y = t;
        s[cnt].k = 0;
    }else{
        s[++cnt].x=find(t);s[cnt].y=l;s[cnt].k=1;//从底端入
        s[++cnt].x=find(t);s[cnt].y=r;s[cnt].k=-1;//从上端出
    }
}
void update(int x,int y){
    while(x<2e5){
        tr[x]+=y;
        x+=x&(-x);
    }
}
int ask(int x){
    int s = 0;
    while(x){
        s+=tr[x];
        x-=x&(-x);
    }

    return s;
}

signed main(){
    cin>>n;
    for(int i =1;i<=2*n;i++){
        cin>>p[i].x>>p[i].y;
        Hash[i]=p[i].x;
    }
    sort(Hash+1,Hash+2*n+1);
    m = unique(Hash+1,Hash+2*n+1)-(Hash+1);
    for(int i=1;i<=2*n;i+=2){
        if(p[i].x==p[i+1].x){//垂直,k=1
            if(p[i].y>p[i+1].y)swap(p[i],p[i+1]);
            insert(1,p[i].y,p[i+1].y,p[i].x);
        }else{
            if(p[i].x>p[i+1].x)swap(p[i],p[i+1]);
            insert(0,p[i].x,p[i+1].x,p[i].y);
        }
    }

    sort(s+1,s+cnt+1);
    for(int i =1;i<=cnt;i++){
        if(!s[i].k)ans+=ask(s[i].r)-ask(s[i].x-1);
        else update(s[i].x,s[i].k);
    }
    cout<<ans<<endl;
}
accuracy: 1
time_ms: 80
memory_kb: 15856
final_rank: 13

code_snippet: #include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
#include <cassert>
#include <cstring>
#include <set>

#define EPS (1e-10)
#define equals(a, b) (fabs((a) - (b)) < EPS)

using namespace std;

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;

struct Point {
    double x, y;
    Point() {}
    Point(double _x, double _y) : 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(x*a, y*a); }
    Point operator / (double a) { return Point(x/a, y/a); }

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

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

    bool operator == (const Point &p) const {
        return equals(x, p.x) && equals(y, p.y);
    }
};

typedef Point Vector;
typedef vector<Point> Polygon;

struct Segment {
    Point p1, p2;
    Segment(Point _p1 = Point(), Point _p2 = Point()) : p1(_p1), p2(_p2) {}
};

typedef Segment Line;


struct Circle {
    Point c;
    double r;
    Circle(Point _c = Point(), double _r = 0.0) : c(_c), r(_r) {}
};

double dot(Vector a, Vector b) {
    return a.x * b.x + a.y * b.y;
}

double cross(Vector a, Vector b) {
    return a.x * b.y - a.y * b.x;
}

bool isOrthogonal(Vector a, Vector b) {
    return equals(dot(a, b), 0.0);
}

bool isOrthogonal(Point a1, Point a2, Point b1, Point b2) {
    return isOrthogonal(a1-a2, b1-b2);
}

bool isOrthogonal(Segment s1, Segment s2) {
    return equals(dot(s1.p2-s1.p1, s2.p2-s2.p1), 0.0);
}

bool isParallel(Vector a, Vector b) {
    return equals(cross(a, b), 0.0);
}

bool isParallel(Point a1, Point a2, Point b1, Point b2) {
    return isParallel(a1-a2, b1-b2);
}

bool isParallel(Segment s1, Segment s2) {
    return equals(cross(s1.p2-s1.p1, s2.p2-s2.p1), 0.0);
}

Point project(Segment s, Point p) {
    Vector base = s.p2 - s.p1;
    double r = dot(p - s.p1, base) / base.norm();
    return s.p1 + base * r;
}

Point reflect(Segment s, Point p) {
    return p + (project(s, p) - p) * 2.0;
}

Point getCrossPoint(Segment s1, Segment s2) {
    Vector base = s2.p2 - s2.p1;
    double d1 = fabs(cross(base, s1.p1 - s2.p1));
    double d2 = fabs(cross(base, s1.p2 - s2.p1));
    double t = d1 / (d1 + d2);
    return s1.p1 + (s1.p2 - s1.p1) * t;
}

int ccw(Point p0, Point p1, Point p2) {
    Vector a = p1 - p0;
    Vector b = p2 - p0;
    if (cross(a, b) > EPS) return COUNTER_CLOCKWISE;
    if (cross(a, b) < -EPS) return CLOCKWISE;
    if (dot(a, b) < -EPS) return ONLINE_BACK;
    if (a.norm() < b.norm()) return ONLINE_FRONT;

    return ON_SEGMENT;
}

bool intersect(Point p1, Point p2, Point p3, Point p4) {
    return (ccw(p1, p2, p3) * ccw(p1, p2, p4) <= 0 && 
            ccw(p3, p4, p1) * ccw(p3, p4, p2) <= 0);
}

bool intersect(Segment s1, Segment s2) {
    return intersect(s1.p1, s1.p2, s2.p1, s2.p2);
}

double getDistanceLP(Line l, Point p);
bool intersect(Circle c, Line l) {
    double d = getDistanceLP(l, c.c);
    return d < c.r || equals(d, c.r);
}

double getDistance(Point a, Point b);
bool intersect(Circle c1, Circle c2) {
    double d = getDistance(c1.c, c2.c);
    return (d < c1.r + c2.r || (equals(d, c1.r + c2.r)));
}

double getDistance(Point a, Point b) {
    return (a-b).abs();
}

double getDistanceLP(Line l, Point p) {
    return abs(cross(l.p2-l.p1, p-l.p1) / (l.p2-l.p1).abs());
}


double getDistanceSP(Segment s, Point p) {
    if (dot(s.p2-s.p1, p-s.p1) < 0.0) return (p-s.p1).abs();
    if (dot(s.p1-s.p2, p-s.p2) < 0.0) return (p-s.p2).abs();
    return getDistanceLP(s, p);
}

double getDistance(Segment s1, Segment s2) {
    if (intersect(s1, s2)) return 0.0;
    return min(min(getDistanceSP(s1, s2.p1), getDistanceSP(s1, s2.p2)),
            min(getDistanceSP(s2, s1.p1), getDistanceSP(s2, s1.p2)));
}

pair<Point, Point> getCrossPoints(Circle c, Line l) {
    assert(intersect(c, l));
    Vector pr = project(l, c.c);
    Vector e = (l.p2 - l.p1) / (l.p2 - l.p1).abs();
    double base = sqrt(c.r * c.r - (pr - c.c).norm());
    return make_pair(pr + e * base, pr - e * base);
}

double arg(Vector p) { return atan2(p.y, p.x); }
Vector polar(double a, double r) { return Point(cos(r) * a, sin(r) * a); }

pair<Point, Point> getCrossPoints(Circle c1, Circle c2) {
    assert(intersect(c1, c2));
    double d = (c1.c - c2.c).abs();
    double a = acos((c1.r * c1.r + d * d - c2.r * c2.r) / (2 * c1.r * d));
    double t = arg(c2.c - c1.c);
    return make_pair(c1.c + polar(c1.r, t + a), c1.c + polar(c1.r, t - a));
}

int contains(Polygon &g, Point p) {
    int n = g.size();
    bool x = false;
    for (int i = 0; i < n; i++) {
        Point a = g[i] - p, b = g[(i + 1) % n] - p;
        if (fabs(cross(a, b)) < EPS && dot(a, b) < EPS) return 1;
        if (a.y > b.y) swap(a, b);
        if (a.y < EPS && EPS < b.y && cross(a, b) > EPS) x = !x;
    }
    return (x ? 2 : 0);
}

Polygon andrewScan(Polygon s) {
    Polygon u, l;
    if (s.size() < 3) return s;
    sort(s.begin(), s.end());
    u.push_back(s[0]);
    u.push_back(s[1]);
    l.push_back(s[s.size() - 1]);
    l.push_back(s[s.size() - 2]);

    for (int i = 2; i < s.size(); i++) {
        for (int n = u.size(); n >= 2 && ccw(u[n-2], u[n-1], s[i]) == COUNTER_CLOCKWISE; n--) {
            u.pop_back();
        }
        u.push_back(s[i]);
    }
    for (int i = s.size() - 3; i >= 0; i--) {
        for (int n = l.size(); n >= 2 && ccw(l[n-2], l[n-1], s[i]) == COUNTER_CLOCKWISE; n--) {
            l.pop_back();
        }
        l.push_back(s[i]);
    }
    reverse(l.begin(), l.end());
    for (int i = u.size() - 2; i >= 1; i--) l.push_back(u[i]);
    return l;
}

#define BOTTOM 0
#define LEFT 1
#define RIGHT 2
#define TOP 3

struct EndPoint {
    Point p;
    int seg, st;
    EndPoint() {}
    EndPoint(Point _p, int _seg, int _st) : p(_p), seg(_seg), st(_st) {}

    bool operator < (const EndPoint &ep) const {
        if (p.y == ep.p.y) {
            return st < ep.st;
        } else return p.y < ep.p.y;
    }
};

EndPoint EP[2 * 100000];

int manhattanIntersection(vector<Segment> S) {
    int n = S.size();
    for (int i = 0, k = 0; i < n; i++) {
        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);
        }
    }

    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) {
            set<int>::iterator b = BT.lower_bound(S[EP[i].seg].p1.x);
            set<int>::iterator e = BT.upper_bound(S[EP[i].seg].p2.x);
            cnt += distance(b, e);
        }
    }
    return cnt;
}

int main() {
    int N;
    scanf("%d", &N);
    vector<Segment> S;
    while (N--) {
        double x1, y1, x2, y2;
        scanf("%lf %lf %lf %lf", &x1, &y1, &x2, &y2);
        Segment seg = Segment(Point(x1, y1), Point(x2, y2));
        S.push_back(seg);
    }
    printf("%d\n", manhattanIntersection(S));
    return 0;
}
accuracy: 1
time_ms: 70
memory_kb: 16712
final_rank: 11

code_snippet: #include <bits/stdc++.h>
using namespace std;

int main()
{
    int n;
    cin >> n;
    vector<tuple<int, int, int, int>> points;
    for (int i = 0; i < n; i++)
    {
        int x1, y1, x2, y2;
        cin >> x1 >> y1 >> x2 >> y2;
        if (x1 == x2)
        {
            if (y1 > y2)
            {
                swap(y1, y2);
            }
            //下の端点
            points.push_back( make_tuple(y1, 0, x1, x2) );
            //上の端点
            points.push_back( make_tuple(y2, 2, x1, x2) );
        }
        else
        {
            if (x1 > x2)
            {
                swap(x1, x2);
            }
            //水平線分
            points.push_back( make_tuple( y1, 1, x1, x2 ) );
        }
    }

    sort( points.begin(), points.end() );
    set<int> T;

    int ans = 0;

    for (int i = 0; i < points.size(); i++)
    {
        auto p = points[i];
        if ( get<1>(p) == 0 ) T.insert(get<2>(p));
        else if ( get<1>(p) == 2 ) T.erase(get<2>(p));
        else
        {
            auto l = T.lower_bound(get<2>(p));
            auto r = T.upper_bound(get<3>(p));
            ans += distance(l, r);
        }
    }

    cout << ans << endl;

    return 0;
}
accuracy: 1
time_ms: 80
memory_kb: 9764
final_rank: 5

code_snippet: #include<bits/stdc++.h>
using namespace std;

const int N = 4e5 + 5;
typedef long long ll;
// 空间开16倍！

struct node 
{
    int l, r, cl, cr, f, w;
}p[N * 4];

struct edgex
{
    int l, r, y;
}ax[N * 4];

struct edgey
{
    int x, y, flag;
}ay[N * 4];

int n, m, mx, cnt, px[N];

void build(int id, int L, int R)
{
    p[id].l = L;
    p[id].r = R;
    p[id].w = p[id].f = 0;
    if(L == R)
    {
        p[id].cl = px[L];
        p[id].cr = px[R];
        return;
    }
    int mid = (L + R) / 2;
    build(id * 2, L, mid);
    build(id * 2 + 1, mid + 1, R);
    p[id].cl = p[id * 2].cl;
    p[id].cr = p[id * 2 + 1].cr;
}

void update(int id, int L, int x)
{
    if(L == p[id].cl && L == p[id].cr)
    {
        p[id].w += x;
        p[id].f += x;
        return;
    }

    if(p[id * 2].cr >= L)
		update(id * 2, L, x);
	else
    	update(id * 2 + 1, L, x);
    p[id].w = p[id * 2].w + p[id * 2 + 1].w;
}

int query(int id, int L, int R)
{
    //cout << id << ' ' << p[id].cl << ' '<< p[id].cr << endl;
    if(L <= p[id].cl && p[id].cr <= R)
        return p[id].w;
    int res = 0;
    if(p[id * 2].cr >= L)
        res += query(id * 2, L, R);
    if(p[id * 2 + 1].cl <= R)
        res += query(id * 2 + 1, L, R);
    return res;
}

bool cmpy(edgey b, edgey c)
{
    return b.y < c.y;
}

bool cmpx(edgex b, edgex c)
{
    return b.y < c.y;
}

int main()
{
    scanf("%d", &n);
    int xa, ya, xb, yb;
    for(int i = 1; i <= n; i ++)
    {
        scanf("%d%d%d%d", &xa, &ya, &xb, &yb);
        if(xa == xb)
        {
            ay[++ m].x = xa;
            ay[m].y = min(ya, yb);
            ay[m].flag = 1;
            ay[++ m].x = xa;
            ay[m].y = max(ya, yb) + 1;
            ay[m].flag = -1;
            px[++cnt] = xa;
        }
        else
        {
            px[++cnt] = ax[++ mx].l = min(xa, xb);
            ax[mx].y = ya;
            px[++cnt] = ax[mx].r = max(xa, xb);
        }
    }

    sort(px + 1, px + cnt + 1);
    int tot = unique(px + 1, px + cnt + 1) - px - 1;
    // for(int i = 1; i <= tot; i ++)
    //     cout << px[i] << ' ';
    // cout <<"tot = "<< tot << endl;
	build(1, 1, tot);
    sort(ax + 1, ax + mx + 1, cmpx);
    sort(ay + 1, ay + m + 1, cmpy);
    
    ll ans = 0;
    int idx = 1;
    for(int i = 1; i <= mx; i ++)
    {
        while(ay[idx].y <= ax[i].y)
        {
            //cout << "update = " << ay[idx].x << endl;
            update(1, ay[idx].x, ay[idx].flag);
            idx ++;
        }
        //cout << "query = " << ax[i].l << ' ' << ax[i].r << endl;
        ans += query(1, ax[i].l, ax[i].r);
    }

    printf("%lld\n", ans);
    return 0;
}
accuracy: 1
time_ms: 40
memory_kb: 16492
final_rank: 8

code_snippet: #include <bits/stdc++.h>

// https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/6/CGL_6_A
// 给定 n 条和 X 轴和 Y 轴平行的直线, 求它们之间的交点个数
// from: cpp.json
#define INF 8e18
#define int long long
using namespace std;

template <typename T>
struct Fenwick {
    int n;
    std::vector<T> a;
    
    Fenwick(int n_ = 0) {
        init(n_);
    }
    
    void init(int n_) {
        n = n_;
        a.assign(n + 1, T{});
    }
    
    void add(int x, const T &v) {
        for (int i = x; i <= n; i += i & -i) {
            a[i] += v;
        }
    }
    
    T sum(int x) {
        T ans{};
        for (int i = x; i > 0; i -= i & -i) {
            ans = ans + a[i];
        }
        return ans;
    }
    
    T rangeSum(int l, int r) {
        if (l > r) return T{};
        return sum(r) - sum(l - 1);
    }
    
    // 前缀和不超过给定值的最小位置的查询
    int select(const T &k) {
        int x = 0;
        T cur{};
        for (int i = 1 << std::__lg(n); i; i /= 2) {
            if (x + i <= n && cur + a[x + i] <= k) {
                x += i;
                cur = cur + a[x];
            }
        }
        return x;
    }
};

struct Event {
    int x, type, y1, y2;  
};

void solve() {
    int n;
    cin >> n;

    vector<tuple<int, int, int, int>> seg(n);
    vector<int> ys;

    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);
        }
        seg[i] = {x1, y1, x2, y2};
        ys.push_back(y1);
        ys.push_back(y2);
    }

    ranges::sort(ys);
    ys.erase(unique(ys.begin(), ys.end()), ys.end());

    auto getY = [&](int y) -> int {
        return lower_bound(ys.begin(), ys.end(), y) - ys.begin() + 1;
    };

    int m = ys.size();

    vector<Event> e;
    for (auto [x1, y1, x2, y2] : seg) {
        if (y1 == y2) {
            int Y = getY(y1);
            e.push_back({x1, 0, Y, 0});
            e.push_back({x2 + 1, 1, Y, 0});
        } else {
            int Y1 = getY(y1);
            int Y2 = getY(y2);
            e.push_back({x1, 2, Y1, Y2});
        }
    }

    sort(e.begin(), e.end(), [&](auto &a, auto &b) {
        if (a.x != b.x) {
            return a.x < b.x;
        }
        return a.type < b.type;
    });

    Fenwick<int> bit(m + 1);
    int ans = 0;
    for (auto &E : e) {
        if (E.type == 0) {
            bit.add(E.y1, 1);
        } else if (E.type == 1) {
            bit.add(E.y1, -1);
        } else {
            ans += bit.rangeSum(E.y1, E.y2);
        }
    } 

    cout << ans << '\n';
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    solve();

    return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 17424
final_rank: 6

code_snippet: #include <bits/stdc++.h>

// 
// from: cpp.json
#define INF 8e18
#define int long long
using namespace std;

template<class T>
struct Point {
    T x; 
    T y; 

    Point(const T &x_ = 0, const T &y_ = 0) : x(x_), y(y_) {}

    template<class U>
    operator Point<U>() {
        return Point<U>(U(x), U(y));
    }

    Point &operator+=(const Point &p) & {
        x += p.x;
        y += p.y;
        return *this;
    }
    
    Point &operator-=(const Point &p) & {
        x -= p.x;
        y -= p.y;
        return *this;
    }
    
    Point &operator*=(const T &v) & {
        x *= v;
        y *= v;
        return *this;
    }
    
    Point &operator/=(const T &v) & {
        x /= v;
        y /= v;
        return *this;
    }
    
    Point operator-() const {
        return Point(-x, -y);
    }
    
    friend Point operator+(Point a, const Point &b) {
        return a += b;
    }
    
    friend Point operator-(Point a, const Point &b) {
        return a -= b;
    }
    
    friend Point operator*(Point a, const T &b) {
        return a *= b;
    }
    
    friend Point operator/(Point a, const T &b) {
        return a /= b;
    }
    
    friend Point operator*(const T &a, Point b) {
        return b *= a;
    }
    
    friend bool operator==(const Point &a, const Point &b) {
        return a.x == b.x && a.y == b.y;
    }
    
    friend std::istream &operator>>(std::istream &is, Point &p) {
        return is >> p.x >> p.y;
    }
    
    friend std::ostream &operator<<(std::ostream &os, const Point &p) {
        return os << "(" << p.x << ", " << p.y << ")";
    }
};

template<class T>
struct Line {
    Point<T> a;  
    Point<T> b;  
    Line(const Point<T> &a_ = Point<T>(), const Point<T> &b_ = Point<T>()) : a(a_), b(b_) {}
};

/*
    计算向量 a 和 b 的点积（内积）
    dot(a, b) = a.x*b.x + a.y*b.y
*/
template<class T>
T dot(const Point<T> &a, const Point<T> &b) {
    return a.x * b.x + a.y * b.y;
}

/*
    计算向量 a 和 b 的叉积（2D 向量的“伪叉积”）
    cross(a, b) = a.x*b.y - a.y*b.x
    正值表示 b 在 a 的逆时针方向，负值表示顺时针方向
*/
template<class T>
T cross(const Point<T> &a, const Point<T> &b) {
    return a.x * b.y - a.y * b.x;
}

/*
    计算点 p 的平方模：|p|^2 = dot(p, p)
*/
template<class T>
T square(const Point<T> &p) {
    return dot(p, p);
}

/*
    计算点 p 的长度（欧几里得范数），返回 double
*/
template<class T>
double length(const Point<T> &p) {
    return std::sqrt(square(p));
}

/*
    计算线段 l 的长度
    通过端点之差的长度来计算
*/
template<class T>
double length(const Line<T> &l) {
    return length(l.a - l.b);
}

/*
    将向量 p 归一化：返回单位向量 p/|p|
    注意：调用者需保证 p != (0,0)
*/
template<class T>
Point<T> normalize(const Point<T> &p) {
    return p / length(p);
}

/*
    判断两条直线（线段） l1, l2 是否平行
    平行当且仅当方向向量叉积为 0
*/
template<class T>
bool parallel(const Line<T> &l1, const Line<T> &l2) {
    return cross(l1.b - l1.a, l2.b - l2.a) == 0;
}

/*
    计算两点 a, b 之间的距离，等价于 |a - b|
*/
template<class T>
double distance(const Point<T> &a, const Point<T> &b) {
    return length(a - b);
}

using LD = long double;    
using P = Point<LD>;       

constexpr LD eps = 0;  

template <typename T>
struct Fenwick {
    int n;
    std::vector<T> a;
    
    Fenwick(int n_ = 0) {
        init(n_);
    }
    
    void init(int n_) {
        n = n_;
        a.assign(n + 1, T{});
    }
    
    void add(int x, const T &v) {
        for (int i = x; i <= n; i += i & -i) {
            a[i] += v;
        }
    }
    
    T sum(int x) {
        T ans{};
        for (int i = x; i > 0; i -= i & -i) {
            ans = ans + a[i];
        }
        return ans;
    }
    
    T rangeSum(int l, int r) {
        if (l > r) return T{};
        return sum(r) - sum(l - 1);
    }
    
    // 前缀和不超过给定值的最小位置的查询
    int select(const T &k) {
        int x = 0;
        T cur{};
        for (int i = 1 << std::__lg(n); i; i /= 2) {
            if (x + i <= n && cur + a[x + i] <= k) {
                x += i;
                cur = cur + a[x];
            }
        }
        return x;
    }
};

struct Event {
    int x, type, y1, y2;  
};

void solve() {
    int n;
    cin >> n;

    vector<tuple<int, int, int, int>> seg(n);
    vector<int> ys;

    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);
        }
        seg[i] = {x1, y1, x2, y2};
        ys.push_back(y1);
        ys.push_back(y2);
    }

    ranges::sort(ys);
    ys.erase(unique(ys.begin(), ys.end()), ys.end());

    auto getY = [&](int y) -> int {
        return lower_bound(ys.begin(), ys.end(), y) - ys.begin() + 1;
    };

    int m = ys.size();

    vector<Event> e;
    for (auto [x1, y1, x2, y2] : seg) {
        if (y1 == y2) {
            int Y = getY(y1);
            e.push_back({x1, 0, Y, 0});
            e.push_back({x2 + 1, 1, Y, 0});
        } else {
            int Y1 = getY(y1);
            int Y2 = getY(y2);
            e.push_back({x1, 2, Y1, Y2});
        }
    }

    sort(e.begin(), e.end(), [&](auto &a, auto &b) {
        if (a.x != b.x) {
            return a.x < b.x;
        }
        return a.type < b.type;
    });

    Fenwick<int> bit(m + 1);
    int ans = 0;
    for (auto &E : e) {
        if (E.type == 0) {
            bit.add(E.y1, 1);
        } else if (E.type == 1) {
            bit.add(E.y1, -1);
        } else {
            ans += bit.rangeSum(E.y1, E.y2);
        }
    } 

    cout << ans << '\n';
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    solve();

    return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 16652
final_rank: 4

code_snippet: #include <bits/stdc++.h>

// 
// from: cpp.json
#define INF 8e18
#define int long long
using namespace std;

template<class T>
struct Point {
    T x; 
    T y; 

    Point(const T &x_ = 0, const T &y_ = 0) : x(x_), y(y_) {}

    template<class U>
    operator Point<U>() {
        return Point<U>(U(x), U(y));
    }

    Point &operator+=(const Point &p) & {
        x += p.x;
        y += p.y;
        return *this;
    }
    
    Point &operator-=(const Point &p) & {
        x -= p.x;
        y -= p.y;
        return *this;
    }
    
    Point &operator*=(const T &v) & {
        x *= v;
        y *= v;
        return *this;
    }
    
    Point &operator/=(const T &v) & {
        x /= v;
        y /= v;
        return *this;
    }
    
    Point operator-() const {
        return Point(-x, -y);
    }
    
    friend Point operator+(Point a, const Point &b) {
        return a += b;
    }
    
    friend Point operator-(Point a, const Point &b) {
        return a -= b;
    }
    
    friend Point operator*(Point a, const T &b) {
        return a *= b;
    }
    
    friend Point operator/(Point a, const T &b) {
        return a /= b;
    }
    
    friend Point operator*(const T &a, Point b) {
        return b *= a;
    }
    
    friend bool operator==(const Point &a, const Point &b) {
        return a.x == b.x && a.y == b.y;
    }
    
    friend std::istream &operator>>(std::istream &is, Point &p) {
        return is >> p.x >> p.y;
    }
    
    friend std::ostream &operator<<(std::ostream &os, const Point &p) {
        return os << "(" << p.x << ", " << p.y << ")";
    }
};

template<class T>
struct Line {
    Point<T> a;  
    Point<T> b;  
    Line(const Point<T> &a_ = Point<T>(), const Point<T> &b_ = Point<T>()) : a(a_), b(b_) {}
};

/*
    计算向量 a 和 b 的点积（内积）
    dot(a, b) = a.x*b.x + a.y*b.y
*/
template<class T>
T dot(const Point<T> &a, const Point<T> &b) {
    return a.x * b.x + a.y * b.y;
}

/*
    计算向量 a 和 b 的叉积（2D 向量的“伪叉积”）
    cross(a, b) = a.x*b.y - a.y*b.x
    正值表示 b 在 a 的逆时针方向，负值表示顺时针方向
*/
template<class T>
T cross(const Point<T> &a, const Point<T> &b) {
    return a.x * b.y - a.y * b.x;
}

/*
    计算点 p 的平方模：|p|^2 = dot(p, p)
*/
template<class T>
T square(const Point<T> &p) {
    return dot(p, p);
}

/*
    计算点 p 的长度（欧几里得范数），返回 double
*/
template<class T>
double length(const Point<T> &p) {
    return std::sqrt(square(p));
}

/*
    计算线段 l 的长度
    通过端点之差的长度来计算
*/
template<class T>
double length(const Line<T> &l) {
    return length(l.a - l.b);
}

/*
    将向量 p 归一化：返回单位向量 p/|p|
    注意：调用者需保证 p != (0,0)
*/
template<class T>
Point<T> normalize(const Point<T> &p) {
    return p / length(p);
}

/*
    判断两条直线（线段） l1, l2 是否平行
    平行当且仅当方向向量叉积为 0
*/
template<class T>
bool parallel(const Line<T> &l1, const Line<T> &l2) {
    return cross(l1.b - l1.a, l2.b - l2.a) == 0;
}

/*
    计算两点 a, b 之间的距离，等价于 |a - b|
*/
template<class T>
double distance(const Point<T> &a, const Point<T> &b) {
    return length(a - b);
}

using LD = long double;    
using P = Point<LD>;       

constexpr LD eps = 0;  

template<typename T>
struct Fenwick {
    int n;
    vector<T> a;
    Fenwick(int _n = 0) { init(_n); }
    void init(int _n) {
        n = _n;
        a.assign(n+1, T{});    
    }
    void add(int x, const T &v) {
        for (int i = x; i <= n; i += i & -i)
            a[i] += v;
    }
    T sum(int x) const {
        T s = T{};
        for (int i = x; i > 0; i -= i & -i)
            s += a[i];
        return s;
    }
    T rangeSum(int l, int r) const {
        if (l > r) return T{};
        return sum(r) - sum(l - 1);
    }
};

struct Event {
    int x, type, y1, y2;  
};

void solve() {
    int n;
    cin >> n;

    vector<tuple<int, int, int, int>> seg(n);
    vector<int> ys;

    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);
        }
        seg[i] = {x1, y1, x2, y2};
        ys.push_back(y1);
        ys.push_back(y2);
    }

    ranges::sort(ys);
    ys.erase(unique(ys.begin(), ys.end()), ys.end());

    auto getY = [&](int y) -> int {
        return lower_bound(ys.begin(), ys.end(), y) - ys.begin() + 1;
    };

    int m = ys.size();

    vector<Event> e;
    for (auto [x1, y1, x2, y2] : seg) {
        if (y1 == y2) {
            int Y = getY(y1);
            e.push_back({x1, 0, Y, 0});
            e.push_back({x2 + 1, 1, Y, 0});
        } else {
            int Y1 = getY(y1);
            int Y2 = getY(y2);
            e.push_back({x1, 2, Y1, Y2});
        }
    }

    sort(e.begin(), e.end(), [&](auto &a, auto &b) {
        if (a.x != b.x) {
            return a.x < b.x;
        }
        return a.type < b.type;
    });

    Fenwick<int> bit(m + 1);
    int ans = 0;
    for (auto &E : e) {
        if (E.type == 0) {
            bit.add(E.y1, 1);
        } else if (E.type == 1) {
            bit.add(E.y1, -1);
        } else {
            ans += bit.rangeSum(E.y1, E.y2);
        }
    } 

    cout << ans << '\n';
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    solve();

    return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 17684
final_rank: 7

code_snippet: #include<iostream>
#include<fstream>
#include<iomanip>
#include<cmath>
#include<vector>
#include<list>
#include<stack>
#include<queue>
#include<deque>
#include<string>
#include<bitset>
#include<algorithm>
#include<ctime>
#include<cstdarg>
#include<assert.h>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<map>
#include<assert.h>
#include<set>
using namespace std;
typedef long long ll;
#define eps (1e-10)
#define equals(a,b) (fabs((a)-(b))<eps)
class Point
{
public:
    double x,y;
    Point(double x=0,double y=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(x*a,y*a);
    }
    Point operator / (double a)
    {
        return Point(x/a,y/a);
    }
    double norm()
    {
        return x*x+y*y;
    }
    double abs()
    {
        return sqrt(norm());
    }
    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;
    }
};
typedef Point Vector;
struct Segment
{
    Point p1,p2;
};
typedef Segment Line;
class Circle
{
public:
    Point c;
    double r;
    Circle(Point c=Point(),double r=0.0):c(c),r(r) {}
};
double dot(Vector a,Vector b)//内积
{
    return a.x*b.x+a.y*b.y;
}
double cross(Vector a,Vector b)//外积
{
    return a.x*b.y-a.y*b.x;
}
bool isOrthogonal(Vector a,Vector b)//是否正交
{
    return equals(dot(a,b),0.0);
}
bool isOrthogonal(Point a1,Point a2,Point b1,Point b2)//是否正交
{
    return isOrthogonal(a1-a2,b1-b2);
}
bool isOrthogonal(Segment s1,Segment s2)//是否正交
{
    return equals(dot(s1.p2-s1.p1,s2.p2-s2.p1),0.0);
}
bool isParallel(Vector a,Vector b)//是否平行
{
    return equals(cross(a,b),0.0);
}
bool isParallel(Point a1,Point a2,Point b1,Point b2)//是否平行
{
    return isParallel(a1-a2,b1-b2);
}
bool isParallel(Segment s1,Segment s2)//是否平行
{
    return equals(cross(s1.p2-s1.p1,s2.p2-s2.p1),0.0);
}
Point project(Segment s,Point p)//点p在线段上的投影
{
    Vector base=s.p2-s.p1;
    double r=dot(p-s.p1,base)/base.norm();
    return s.p1+base*r;
}
Point reflect(Segment s,Point p)//映像，p关于s的对称点
{
    return p+(project(s,p)-p)*2.0;
}
double getDistance(Point a,Point b)//点与点之间的距离
{
    return (a-b).abs();
}
double getDistanceLP(Line l,Point p)//点与线之间的距离
{
    return abs(cross(l.p2-l.p1,p-l.p1)/(l.p2-l.p1).abs());
}
double getDistanceSP(Segment s,Point p)//点与线段之间的距离
{
    if (dot(s.p2-s.p1,p-s.p1)<0.0)return (p-s.p1).abs();
    if (dot(s.p1-s.p2,p-s.p2)<0.0)return (p-s.p2).abs();
    return getDistanceLP(s,p);
}
bool intersect(Segment s1,Segment s2);//线段是否相交
double getDistance(Segment s1,Segment s2)//线段与线段之间的距离
{
    if (intersect(s1,s2))return 0.0;
    return min(min(getDistanceSP(s1,s2.p1),getDistanceSP(s1,s2.p2)),
               min(getDistanceSP(s2,s1.p1),getDistanceSP(s2,s1.p2)));
}
static const int COUNTER_CLOCKWISE=1;//p2在p0->p1的逆时针
static const int CLOCKWISE=-1;//p2在p0->p1的顺时针
static const int ONLINE_BACK=2;//共线p2->p0->p1
static const int ONLINE_FRONT=-2;//共线p0->p1->p2
static const int ON_SEGMENT=0;//共线p0->p2->p1
int ccw(Point p0,Point p1,Point p2)
{
    Vector a=p1-p0;
    Vector b=p2-p0;
    if (cross(a,b)>eps)return COUNTER_CLOCKWISE;
    if (cross(a,b)<-eps)return CLOCKWISE;
    if (dot(a,b)<-eps)return ONLINE_BACK;
    if (a.norm()<b.norm())return ONLINE_FRONT;
    return ON_SEGMENT;
}
bool intersect(Point p1,Point p2,Point p3,Point p4)//线段p1p2,p3p4是否相交
{
    return (ccw(p1,p2,p3)*ccw(p1,p2,p4)<=0&&
            ccw(p3,p4,p1)*ccw(p3,p4,p2)<=0);
}
bool intersect(Segment s1,Segment s2)//线段与线段是否相交
{
    return intersect(s1.p1,s1.p2,s2.p1,s2.p2);
}
bool intersect(Circle c,Line l)//圆与线是否相交//自己写的
{
    return c.r>=getDistanceLP(l,c.c);
}
bool intersect(Circle c1,Circle c2)//圆与圆是否相交//自己写的
{
    return c1.r+c2.r>=getDistance(c1.c,c2.c);
}
Point getCrossPoint(Segment s1,Segment s2)//线段的交点
{
    Vector base=s2.p2-s2.p1;
    double d1=abs(cross(base,s1.p1-s2.p1));
    double d2=abs(cross(base,s1.p2-s2.p1));
    double t=d1/(d1+d2);
    return s1.p1+(s1.p2-s1.p1)*t;
}
pair<Point,Point> getCrossPoint(Circle c,Line l)
{
    assert(intersect(c,l));
    Vector pr=project(l,c.c);
    Vector e=(l.p2-l.p1)/(l.p2-l.p1).abs();
    double base=sqrt(c.r*c.r-(pr-c.c).norm());
    return make_pair(pr+e*base,pr-e*base);
}
double arg(Vector p)
{
    return atan2(p.y,p.x);
}
Vector polar(double a,double r)
{
    return Point(cos(r)*a,sin(r)*a);
}
pair<Point,Point> getCrossPoint(Circle c1,Circle c2)
{
    assert(intersect(c1,c2));
    double d=(c1.c-c2.c).abs();
    double a=acos((c1.r*c1.r+d*d-c2.r*c2.r)/(2*c1.r*d));
    double t=arg(c2.c-c1.c);
    return make_pair(c1.c+polar(c1.r,t+a),c1.c+polar(c1.r,t-a));
}
typedef vector<Point> Polygon;
static const int IN=2;
static const int ON=1;
static const int OUT=0;
int contains(Polygon g,Point p)//点与多边形的位置
{
    int n=g.size();
    bool x=false;
    for (int i=0; i<n; ++i)
    {
        Point a=g[i]-p,b=g[(i+1)%n]-p;
        if (abs(cross(a,b))<eps&&dot(a,b)<eps)return 1;
        if (a.y>b.y)swap(a,b);
        if (a.y<eps&&eps<b.y&&cross(a,b)>eps)x=!x;
    }
    return (x? 2:0);
}
Polygon andrewScan(Polygon s)//安德鲁算法求凸包
{
    Polygon u,l;
    if (s.size()<3)return s;
    sort(s.begin(),s.end());
    u.push_back(s[0]);
    u.push_back(s[1]);
    l.push_back(s[s.size()-1]);
    l.push_back(s[s.size()-2]);
    for (int i=2; i<s.size(); ++i)
    {
        for (int n=u.size(); n>=2&&ccw(u[n-2],u[n-1],s[i])==COUNTER_CLOCKWISE; --n)//书上改之前!=CLOCKWISE，这样会把同一条线上的点给去掉
            u.pop_back();
        u.push_back(s[i]);
    }
    for (int i=s.size()-3; i>=0; --i)
    {
        for (int n=l.size(); n>=2&&ccw(l[n-2],l[n-1],s[i])==COUNTER_CLOCKWISE; --n)//书上改之前!=CLOCKWISE，这样会把同一条线上的点给去掉
            l.pop_back();
        l.push_back(s[i]);
    }
    reverse(l.begin(),l.end());
    for (int i=u.size()-2; i>=1; --i)
        l.push_back(u[i]);
    return l;
}
//端点种类
#define BOTTOM 0
#define LEFT 1
#define RIGHT 2
#define TOP 3
class EndPoint
{
public:
    Point p;
    int seg,st;//线段id，端点种类
    EndPoint() {}
    EndPoint(Point p,int seg,int st):p(p),seg(seg),st(st) {}
    bool operator < (const EndPoint &ep)const
    {
        return p.y==ep.p.y? st<ep.st:p.y<ep.p.y;
    }
};
EndPoint EP[2*100000];
int manhattanIntersection(vector<Segment> S)
{
    int n=S.size();
    for (int i=0,k=0; i<n; ++i) //调整端点使得p1p2左小右大
    {
        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);
        }
    }
    sort(EP,EP+2*n);//按y升序排列

    set<int>BST;
    BST.insert(1000000001);
    int cnt=0;
    for (int i=0; i<2*n; ++i)
        if (EP[i].st==TOP)//删除上端
            BST.erase(EP[i].p.x);
        else if (EP[i].st==BOTTOM)//删除下端
            BST.insert(EP[i].p.x);
        else if (EP[i].st==LEFT)
        {
            set<int>::iterator b=BST.lower_bound(S[EP[i].seg].p1.x);
            set<int>::iterator e=BST.upper_bound(S[EP[i].seg].p2.x);
            cnt+=distance(b,e);
        }
    return cnt;
}
int n;
Segment s;
vector<Segment>v;
int main()
{
    cin>>n;
    for (int i=0; i<n; ++i)
    {
        cin>>s.p1.x>>s.p1.y>>s.p2.x>>s.p2.y;
        v.push_back(s);
    }
    cout<<manhattanIntersection(v)<<"\n";
}
accuracy: 1
time_ms: 120
memory_kb: 17096
final_rank: 17

code_snippet: #include <bits/stdc++.h>
#define lo(i, n, m) for (int i = n; i < m; i++)
#define loe(i, n, m) for (int i = n; i <= m; i++)
#define mk make_pair
using namespace std;
typedef pair<int, int> Point;
struct Node {
    Point s, t;
    int id; 
    Node (const Point &ns = Point(0, 0), const Point &nt = Point(0, 0), int nid = 0) : s(ns), t(nt), id(nid) {}
    bool operator < (const Node &n) const {
        if (s.first != n.s.first) return s.first < n.s.first;
        return id < n.id;
    }   
};
const int LIM = 3e5 + 10; 
int cur;
Node d[LIM];
int main(void) {
    ios::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);
    int n;
    cin >> n;
    lo(i, 0, n) {
        Point s, t;
        cin >> s.first >> s.second >> t.first >> t.second;
        if (s.first !=  t.first) {
            if (s.first < t.first) {
                d[cur++] = Node(s, mk(0, 0), 1); 
                d[cur++] = Node(t, mk(0, 0), 3); 
            } else {
                d[cur++] = Node(t, mk(0, 0), 1); 
                d[cur++] = Node(s, mk(0, 0), 3); 
            }
        } else d[cur++] = Node(s, t, 2); 
    }   
    sort(d, d + cur);
    set<int> act;
    int ans = 0;
    lo(i, 0, cur) {
        if (d[i].id == 1) {
            act.insert(d[i].s.second);
        } else if (d[i].id == 2) {
            set<int>::iterator ite = act.lower_bound(min(d[i].s.second, d[i].t.second));
            for (; ite != act.end() && *ite <= max(d[i].s.second,    d[i].t.second);    ite++, ans++);
        } else {
            act.erase(act.find(d[i].s.second));
        }
    }
    cout << ans<<"\n";
    return 0;
}
accuracy: 1
time_ms: 60
memory_kb: 12128
final_rank: 3

code_snippet: #include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <queue>
#include <cmath>
#include <set>
using namespace std;
#define EPS  (1e-10)
#define equals(a,b) (fabs((a) - (b)) < EPS)

// 点类
class Point {
public :
    double x, y;
    Point() {};
    Point(double x, double y) :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(x * a, y * a); }
    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 fabs(x - p.x) < EPS && fabs(y - p.y) < EPS;
    }
};
// 线段类
class Segment {
public:
    Point p1, p2;
    Segment() {};
    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;
    int seg, st; // 线段的ID，端点的种类
    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) {
            return st < ep.st;
        }else {
            return p.y < ep.p.y;
        }
    }

};
EndPoint EP[2 * 1000010];

// 线段相交问题，曼哈顿几何
int manhattanIntersection(vector<Segment> S) {
    int n = S.size();
    //按照端点的y坐标升序排序
    sort(EP, EP + (2 * n));

    set<int> BT;           
    BT.insert(10000000001); 
    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) {
            set<int>::iterator b = BT.lower_bound(S[EP[i].seg].p1.x);
            set<int>::iterator e = BT.upper_bound(S[EP[i].seg].p2.x);

            // 加上b到e距离
            cnt += distance(b, e);
        }

    }
    return cnt;
}
int main() {
    vector<Segment> S;
    Segment seg;
    int n , k = 0;
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%lf %lf %lf %lf", &seg.p1.x, &seg.p1.y, &seg.p2.x, &seg.p2.y);
        //调整端点p1、p2，保证左小右大
        if (seg.p1.y == seg.p2.y) {
            if (seg.p1.x > seg.p2.x)
                swap(seg.p1, seg.p2);
        }
        else if (seg.p1.y > seg.p2.y) {
            swap(seg.p1, seg.p2);
        }

        // 将水平线段添加到端点列表
        if (seg.p1.y == seg.p2.y) {
            EP[k++] = EndPoint(seg.p1, i, LEFT);
            EP[k++] = EndPoint(seg.p2, i, RIGHT);
        }
        else { // 将垂直线段添加到端点列表
            EP[k++] = EndPoint(seg.p1, i, BOTTOM);
            EP[k++] = EndPoint(seg.p2, i, TOP);
        }
        S.push_back(seg);
    }

    printf("%d\n", manhattanIntersection(S));
    return 0;
}
accuracy: 1
time_ms: 60
memory_kb: 18284
final_rank: 12

code_snippet: #include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <queue>
#include <cmath>
#include <set>
using namespace std;
#define EPS  (1e-10)
#define equals(a,b) (fabs((a) - (b)) < EPS)

// 点类
class Point {
public :
    double x, y;
    Point() {};
    Point(double x, double y) :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(x * a, y * a); }
    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 fabs(x - p.x) < EPS && fabs(y - p.y) < EPS;
    }
};
// 线段类
class Segment {
public:
    Point p1, p2;
    Segment() {};
    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;
    int seg, st; // 线段的ID，端点的种类
    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) {
            return st < ep.st;
        }else {
            return p.y < ep.p.y;
        }
    }

};
EndPoint EP[2 * 1000010];

// 线段相交问题，曼哈顿几何
int manhattanIntersection(vector<Segment> S) {
    int n = S.size();
    //按照端点的y坐标升序排序
    sort(EP, EP + (2 * n));

    set<int> BT;            // 二叉搜索树
    BT.insert(10000000001); // 设置标记
    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) {
            set<int>::iterator b = BT.lower_bound(S[EP[i].seg].p1.x);
            set<int>::iterator e = BT.upper_bound(S[EP[i].seg].p2.x);

            // 加上b到e距离
            cnt += distance(b, e);
        }

    }
    return cnt;
}
int main() {
    vector<Segment> S;
    Segment seg;
    int n , k = 0;
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%lf %lf %lf %lf", &seg.p1.x, &seg.p1.y, &seg.p2.x, &seg.p2.y);
        //调整端点p1、p2，保证左小右大
        if (seg.p1.y == seg.p2.y) {
            if (seg.p1.x > seg.p2.x)
                swap(seg.p1, seg.p2);
        }
        else if (seg.p1.y > seg.p2.y) {
            swap(seg.p1, seg.p2);
        }

        // 将水平线段添加到端点列表
        if (seg.p1.y == seg.p2.y) {
            EP[k++] = EndPoint(seg.p1, i, LEFT);
            EP[k++] = EndPoint(seg.p2, i, RIGHT);
        }
        else { // 将垂直线段添加到端点列表
            EP[k++] = EndPoint(seg.p1, i, BOTTOM);
            EP[k++] = EndPoint(seg.p2, i, TOP);
        }
        S.push_back(seg);
    }

    printf("%d\n", manhattanIntersection(S));
    return 0;
}
accuracy: 1
time_ms: 60
memory_kb: 19132
final_rank: 14

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+50;//注意修改大小
const double eps=1e-8;
const double PI=acos(1.0);
const double INF=1e9;//无穷大，视情况修改
#define sgn2(x) ((x)>eps?1:((x)<-eps?2:0))//x>0:1;x<0:2;x=0:0.
#define zero(x) (((x)>0?(x):-(x))<eps)//x=0返回1,否则返回0
long long read(){long long x=0,f=1;char c=getchar();while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}while(isdigit(c)){x=x*10+c-'0';c=getchar();}return x*f;}
ll qpow(ll x,ll q,ll Mod){ll ans=1;while(q){if(q&1)ans=ans*x%Mod;q>>=1;x=(x*x)%Mod;}return ans%Mod;}


//-----------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------点------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------------------------------//
inline double R_to_D(double rad){ return 180/PI*rad; }//弧度转角度
inline double D_to_R(double D){ return PI/180*D; }//角度转弧度
int sgn(double x){
    if(fabs(x) < eps)return 0;//x==0
    if(x < 0)return -1;//x<0
    return 1;//x>0
}//!三态函数sgn用于判断相等，减少精度误差问题
struct Point{
    double x, y;
    Point(double x = 0, double y = 0):x(x), y(y){}//构造函数
};
typedef Point Vector;//!注意区分点和向量
typedef vector<Point> Polygon;//定义多边形:即多个Point顺序组成的
Vector operator + (Vector A, Vector B){return Vector(A.x + B.x, A.y + B.y);}//向量 + 向量 = 向量，点 + 向量 = 向量
Vector operator - (Point A, Point B){return Vector(A.x - B.x, A.y - B.y);}//点 - 点 = 向量(向量AB = B - A)
Vector operator * (Vector A, double p){return Vector(A.x * p, A.y * p);}//向量 * 数 = 向量
Vector operator / (Vector A, double p){return Vector(A.x / p, A.y / p);}//!向量 / 数= 向量
bool operator < (const Point& A, const Point& B) {return A.x < B.x || (A.x == B.x && A.y < B. y);}//点or向量 的比较函数(优先横向排序)
bool operator == (const Point& A, const Point& B){return !sgn(A.x - B.x) && !sgn(A.y - B.y);}//点or向量 的相等函数
double Polar_angle(Vector A){return atan2(A.y, A.x);}//求极角:在极坐标系中，平面上任何一点到极点的连线和极轴的夹角叫做极角。单位弧度rad
double Dot(Vector A, Vector B){return A.x * B.x + A.y * B.y;}//点积(满足交换律)：a·b=|a||b|cos<a,b> A.x*B.x+A.y*B.y;
double Cross(Vector A, Vector B){return A.x *  B.y - B.x * A.y;}//向量的叉积(不满足交换律)：等于两向量有向面积的二倍(若B在A的逆时针方向，则为正值;顺时针则为负值;共线则为0).cross(x, y) = -cross(y, x)
double LeftTest_Point(Point A, Point B, Point C){return Cross(B - A, C - B);}//判断向量BC是不是向AB的逆时针方向（左边）转(ToLeftTest);也可看作一个点C是否在向量AB的左边:是则>0,不是则<0,共线则=0
double LeftTest_Vector(Vector A, Vector B){return Cross(A,B);}//判断向量B是不是向量A的逆时针方向（左边）:是则>0,不是则<0,共线则=0
double Length(Vector A){return sqrt(Dot(A, A));}//取模
double Angle(Vector A, Vector B){return acos(Dot(A, B) / Length(A) / Length(B));}//计算两向量夹角(Angle),返回值为弧度制下的夹角
double Area2(Point A, Point B, Point C){return Cross(B - A, C - A);}//交点为A的两个向量AB和AC,然后求这两个向量的叉积(叉乘),ABxAC=平行四边形的面积
double Dist(Point A,Point B){return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));}
Vector Normal(Vector A) {double L = Length(A);return Vector(-A.y / L, A.x / L);}//向量A的法向量：向量A逆时针旋转九十度之后的单位向量
Vector Format(Vector A) {double L = Length(A);return Vector(A.x / L,A.y / L);}//向量A的单位向量化
Vector Rotate(Vector A, double rad){return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad));}//向量A逆时针旋转后的向量:x'=xcosa -ysina, y'= xsina+ycosa,rad:弧度且为逆时针旋转的角
Point Turn_B(Point A, Point B, double rad){
    double x = (A.x-B.x) * cos(rad) + (A.y-B.y) * sin(rad) + B.x;
    double y = - (A.x-B.x) * sin(rad) + (A.y-B.y) * cos(rad) + B.y; 
    return Point(x,y);
}//将点A绕点B顺时针旋转rad(弧度)


//-----------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------直线----------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------------------------------//
struct Line{
    Vector v;//方向向量。左边就是对应的半平面
    Point p;//直线上任意一点
    Line(Vector v, Point p):v(v), p(p) {}
    //如果需要使用极角就使用下面的代码，主要注释上面一行
    // double deg;//极角
    // Line(Vector v,Point p):p(p), v(v){deg = atan2(v.y, v.x);}
    // bool operator < (const Line& L)const {//排序时使用的比较运算符 由x正向逆时针到x正向
    //     return deg < L.deg;
    // }
};//直线定义:P'=P+v*t
struct Segment {
    Point p1, p2;
	Segment() {};
	Segment(Point p1, Point p2) :p1(p1), p2(p2) {};
};//线段定义:两个端点
int Relation(Point A, Point B, Point C){int c = sgn(Cross((B - A), (C - A)));if(c < 0) return 1;else if(c > 0) return -1;return 0;}//点C和直线AB关系:1在左侧;-1在右侧;0在直线上.
Point Get_line_intersection(Point P,Vector V,Point Q,Vector W){
    Vector U = P - Q;double t = Cross(W, U) / Cross(V, W);return P + V * t;
}//两直线交点:(直线AB:A+tv(v为向量AB,t为参数,A为起点)).调用前要确保两直线p + tv和Q + tw之间有唯一交点,当且仅当Corss(v, w) != 0;（t是参数）
double Distance_point_to_line(Point P, Point A, Point B){Vector v1 = B - A, v2 = P - A;return fabs(Cross(v1, v2) / Length(v1));}//如果不取绝对值，那么得到的是有向距离}//点P到直线AB的距离
double Distance_point_to_segment(Point P, Point A, Point B)
{
    if(A == B) return Length(P - A);//（如果重合那么就是两个点之间的距离，直接转成向量求距离即可）
    Vector v1 = B - A, v2 = P - A, v3 = P - B;
    if(sgn(Dot(v1, v2)) < 0) return Length(v2);//A点左边
    if(sgn(Dot(v1, v3)) > 0)return Length(v3);//B点右边
    return fabs(Cross(v1, v2) / Length(v1));//垂线的距离
}//点P到线段AB的距离:垂线距离或者PA或者PB距离
bool OnSegment(Point P, Point A, Point B){return sgn(Cross(A-P, B-P)) == 0 && sgn(Dot(A-P, B-P)) <= 0;}//判断点p是否在线段AB上(包含端点AB，如果不包含AB则<=改为<)
bool Segment_proper_intersection(Point a1, Point a2, Point b1, Point b2){
    double c1 = Cross(a2-a1, b1-a1), c2 = Cross(a2-a1, b2-a1);double c3 = Cross(b2-b1, a1-b1), c4 = Cross(b2-b1, a2-b1);
    //if判断控制是否允许线段在端点处相交，根据需要添加
    if(!sgn(c1) || !sgn(c2) || !sgn(c3) || !sgn(c4)){
        bool f1 = OnSegment(b1, a1, a2), f2 = OnSegment(b2, a1, a2), f3 = OnSegment(a1, b1, b2), f4 = OnSegment(a2, b1, b2);
        bool f = (f1|f2|f3|f4);
        return f;
    }
    return (sgn(c1)*sgn(c2) < 0 && sgn(c3)*sgn(c4) < 0);
}//判断线段a1a2与b1b2是否相交（if控制端点相交）
Point Get_line_projection(Point P, Point A, Point B){Vector v = B - A;return A + v * (Dot(v, P - A) / Dot(v, v));}//求点P在直线AB上的投影点
Point FootPoint(Point P, Point A, Point B){
    Vector x = P - A, y = P - B, z = B - A;
    double len1 = Dot(x, z) / Length(z), len2 = - 1.0 * Dot(y, z) / Length(z);//分别计算AP,BP在AB,BA上的投影
    return A + z * (len1 / (len1 + len2));//点A加上向量AF
}//求点P到直线AB的垂足
Point Symmetry_PL(Point P, Point A, Point B){return P + (FootPoint(P, A, B) - P) * 2; }//求点P到直线AB的对称点
// 线段相交问题，曼哈顿几何
struct EndPoint{
    Point p;
    int seg, st; // 线段的ID，端点的种类:BOTTOM 0、LEFT 1、RIGHT 2、TOP 3
    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) return st < ep.st;
        else return p.y < ep.p.y;
    }
};// 用于求平面内线段交点个数
int manhattanIntersection(vector<Segment>S) {
    vector<EndPoint>EP;
	int n = S.size();
	for (int i = 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.push_back(EndPoint(S[i].p1, i, 1));
			EP.push_back(EndPoint(S[i].p2, i, 2));
		}else { // 将垂直线段添加到端点列表
			EP.push_back(EndPoint(S[i].p1, i, 0));
			EP.push_back(EndPoint(S[i].p2, i, 3));
		}
	}
	sort(EP.begin(),EP.end());//按照端点的y坐标升序排序
	set<int> BT;			// 二叉搜索树
	BT.insert(10000000001); // 设置标记
	int cnt = 0;
	for (int i = 0; i < 2 * n; i++) {
		if (EP[i].st == 3){
            BT.erase(EP[i].p.x); //删除上端点
        }
		else if (EP[i].st == 0){
            BT.insert(EP[i].p.x);
        }
		else if (EP[i].st == 1) {
			set<int>::iterator b = BT.lower_bound(S[EP[i].seg].p1.x);
			set<int>::iterator e = BT.upper_bound(S[EP[i].seg].p2.x);
			cnt += distance(b, e);// 加上b到e距离
		}
	}
	return cnt;
}

//-----------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------多边形----------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------------------------------------//
//外心：三边中垂线交点，到三角形三个顶点距离相同（外接圆圆心）
//内心：角平分线的交点，到三角形三边的距离相同（内切圆圆心）
//垂心：三条垂线的交点
//重心：三条中线的交点，到三角形三顶点距离的平方和最小的点，三角形内到三边距离之积最大的点(x=(x1+x2+x3),y=(y1+y2+y3))
double Convex_polygon_area(Point* p, int n){//逆时针储存所有顶点,下标从0开始
    double area = 0;for(int i = 1; i <= n - 2; ++ i)area += Cross(p[i] - p[0], p[i + 1] - p[0]);return area / 2;//return fabs(area / 2);//不加的话求的是有向面积，逆时针为正，顺时针为负
}//求凸多边形的有向面积
double Polygon_area(Point* p, int n){//逆时针储存所有顶点,下标从0开始
    double area = 0;for(int i = 1; i <= n - 2; ++ i)area += Cross(p[i] - p[0], p[i + 1] - p[0]);return area / 2;
}//求非凸多边形的有向面积
int is_point_in_polygon(Point p, Point* poly,int n){//待判断的点和该多边形的所有点的合集
    int wn = 0;
    for(int i = 0; i < n; ++i){
        if(OnSegment(p, poly[i], poly[(i+1)%n])) return -1;
        int k = sgn(Cross(poly[(i+1)%n] - poly[i], p - poly[i])),d1 = sgn(poly[i].y - p.y),d2 = sgn(poly[(i+1)%n].y - p.y);
        if(k > 0 && d1 <= 0 && d2 > 0) wn++;
        if(k < 0 && d2 <= 0 && d1 > 0) wn--;
    }
    if(wn != 0)return 1;
    return 0;
}//判断点P是否在多边形内，若点在多边形内返回1，在多边形外部返回0，在多边形上返回-1
//判断点P是否在凸多边形内,只需要判断点P是否在所有边的左边（按逆时针顺序排列的顶点集）可以使用LeftTest_Point
int is_convex(Point* p,int n){int s[3]={1,1,1};for(int i=0;i<n&&s[1]|s[2];i++)s[sgn2(Cross(p[(i+1)%n]-p[i],p[(i+2)%n]-p[i]))]=0;return s[1]|s[2];}//判定凸多边形,允许相邻边共线.顶点按顺时针或逆时针给出
int is_convex_v2(Point* p,int n){int s[3]={1,1,1};for (int i=0;i<n&&s[0]&&s[1]|s[2];i++)s[sgn2(Cross(p[(i+1)%n]-p[i],p[(i+2)%n]-p[i]))]=0;return s[0]&&s[1]|s[2];}//判定凸多边形,不允许相邻边共线.顺时针或逆时针给出
int inside_convex(Point q,Point* p,int n){int s[3]={1,1,1};for (int i=0;i<n&&s[1]|s[2];i++)s[sgn2(Cross(p[(i+1)%n]-p[i],q-p[i]))]=0;return s[1]|s[2];}//判点q在凸多边形内或边上,顶点按顺时针或逆时针给出
int inside_convex_v2(Point q,Point* p,int n){int s[3]={1,1,1};for (int i=0;i<n&&s[0]&&s[1]|s[2];i++)s[sgn2(Cross(p[(i+1)%n]-p[i],q-p[i]))]=0;return s[0]&&s[1]|s[2];}//判点q在凸多边形内,顶点按顺时针或逆时针给出,在多边形边上返回0
int inside_polygon(Point q,Point* p,int n,int on_edge=1){//on_edge表示点在多边形边上时的返回值,默认为1
	Point q2;int i=0,count=0;
    const int offset=10000;//offset为多边形坐标上限,根据题意修改
	while (i<n){
        for (count=i=0,q2.x=rand()+offset,q2.y=rand()+offset;i<n;i++){
            if (zero(Cross(q-p[(i+1)%n],p[i]-p[(i+1)%n]))&&(p[i].x-q.x)*(p[(i+1)%n].x-q.x)<eps&&(p[i].y-q.y)*(p[(i+1)%n].y-q.y)<eps)return on_edge;
			else if (zero(Cross(q-p[i],q2-p[i])))break;
			else if (Cross(q-q2,p[i]-q2)*Cross(q-q2,p[(i+1)%n]-q2)<-eps&&Cross(p[i]-p[(i+1)%n],q-p[(i+1)%n])*Cross(p[i]-p[(i+1)%n],q2-p[(i+1)%n])<-eps)count++;
        }
    }
    if(count&1)return 2;return 0;
}//判点在任意多边形内,顶点按顺时针或逆时针给出.点q在多边形内则为2,在边上则为1(可以修改on_edge),在外则为0

int opposite_side(Point p1,Point p2,Point l1,Point l2){return Cross(l1-l2,p1-l2)*Cross(l1-l2,p2-l2)<-eps;}
int dot_online_in(Point p,Point l1,Point l2){return zero(Cross(p-l2,l1-l2))&&(l1.x-p.x)*(l2.x-p.x)<eps&&(l1.y-p.y)*(l2.y-p.y)<eps;}
int inside_polygon(Point l1,Point l2,Point* p,int n){
    const int MAXN=1000;//注意根据n的范围进行修改
	Point t[MAXN],tt;int i,j,k=0;
	if (!inside_polygon(l1,p,n)||!inside_polygon(l2,p,n))return 0;
	for (i=0;i<n;i++){
        if (opposite_side(l1,l2,p[i],p[(i+1)%n])&&opposite_side(p[i],p[(i+1)%n],l1,l2))return 0;
		else if (dot_online_in(l1,p[i],p[(i+1)%n]))t[k++]=l1;
		else if (dot_online_in(l2,p[i],p[(i+1)%n]))t[k++]=l2;
		else if (dot_online_in(p[i],l1,l2))t[k++]=p[i];
    }
	for (i=0;i<k;i++){
        for (j=i+1;j<k;j++){
			tt.x=(t[i].x+t[j].x)/2;tt.y=(t[i].y+t[j].y)/2;
			if(!inside_polygon(tt,p,n))return 0;			
		}
    }	
	return 1;
}//判线段l1l2在任意多边形内,顶点按顺时针或逆时针给出,与边界相交或在内部返回1，否则返回0
Point Polygon_center(Point *p, int n) {
    Point ans(0, 0);
    if(Polygon_area(p, n) == 0)return ans;
    for (int i = 0; i < n; i++)ans = ans + (p[i] + p[(i + 1) % n]) * Cross(p[i], p[(i + 1) % n]); //面积有正负
    return ans / Polygon_area(p, n) / 6.;
}//多边形重心,将多边形三角剖分，算出每个三角形重心（三角形重心是3点坐标平均值）对每个三角形有向面积求加权平均值
bool cmp_ConvexHull(Point A,Point B){return A.y < B.y || (A.y == B.y && A.x < B. x);}//竖向排序，默认从下左角开始逆时针输出
int ConvexHull(Point* p, int n, Point* ch){//下标都是从0开始，ch按照逆时针存储的
    sort(p, p + n);int m = 0;
    for(int i = 0; i < n;i++){//下凸包
        //如果叉积<=0说明新边斜率小说明已经不是凸包边了，赶紧踢走
        while(m > 1 && Cross(ch[m - 1] - ch[m - 2], p[i] - ch[m - 2]) <= 0)m -- ;
        ch[m ++ ] = p[i];//<=:一条边有两给端点;<:边上可以有多个输入点 注意根据题意进行修改(求凸包直径的时候是<=)
    }
    int k = m;
    for(int i = n - 2; i >= 0;i--){//上凸包
        while(m > k && Cross(ch[m - 1] - ch[m - 2], p[i] - ch[m - 2]) <= 0)m -- ;
        ch[m ++ ] = p[i];//<=:一条边有两给端点;<:边上可以有多个输入点 注意根据题意进行修改(求凸包直径的时候是<=)
    }
    if(n > 1) m -- ;return m;//返回凸包顶点个数
}//计算凸包,输入点数组p.输出点数组ch.输入不能有重复的点，函数执行完后的输入点的顺序将被破坏(因为要排序，可以加一个数组存原来的id)
double Rotating_calipers(Point* con,int n){//传入最小凸包的点数组
    int op = 1;double ans = 0;
    for(int i = 0; i < n; ++ i){
        while(Cross((con[i] - con[op]), (con[i + 1] - con[i])) < Cross((con[i] - con[op + 1]), (con[i + 1] - con[i])))op = (op + 1) % n;//（写成<=会被两个点的数据卡掉，所以必须写成<）
            ans = max(ans, max(Dot(con[i] - con[op],con[i] - con[op]), Dot(con[i + 1] - con[op],con[i + 1] - con[op])));
    }
    return ans;
}//旋转卡壳,返回凸包的直径的平方
Polygon CutPolygon(Polygon poly,const Point& a,const Point& b) {//poly中的点从0开始
    Polygon newpoly;int n=poly.size();
    for(int i=0; i<n; i++){
        Point c=poly[i],d=poly[(i+1)%n];
        if(sgn(Cross(b-a,c-a))>=0)newpoly.push_back(c);//有向直线的左侧所有点(包括交点)
        if(sgn(Cross(b-a,c-d))!=0){
            Point ip=Get_line_intersection(a,b-a,c,d-c);
            if(OnSegment(ip,c,d))newpoly.push_back(ip);
        }
    }
    return newpoly;
}//有向直线ab切割多边形,返回有向直线的左侧所有点，包括了直线ab和多边形的交点    
double Divide_Conquer(Point* a,Point* b,int l,int r){//a是原数组,原数组需要以x从左到右进行排序,即对Point数组进行最基本的排序(<)
    if(l==r)return INF;//注意修改无穷大的值，视情况而定
    if(l+1==r)return Dist(a[l],a[r]);
    int mid=(l+r)>>1;
    double ans=min(Divide_Conquer(a,b,l,mid),Divide_Conquer(a,b,mid+1,r));
    int len=0;
    for(int i=l;i<=r;i++)if(fabs(a[mid].x-a[i].x)<=ans)b[len++]=a[i];
    sort(b,b+len,cmp_ConvexHull);
    for(int i=0;i<len;i++){
        for(int j=i+1;j<len;j++){
            if(b[j].y-b[i].y>ans)break;
            ans=min(ans,Dist(b[i],b[j]));
        }
    }
    return ans;
}//平面最近点对:n个点中最近的两个点的距离.O(nlogn)
int n,T;
int main(){
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    vector<Segment>s;
    cin>>n;
    for(int i=0;i<n;i++){
        Segment a;
        cin>>a.p1.x>>a.p1.y>>a.p2.x>>a.p2.y;
        s.push_back(a);
    }
    cout<<manhattanIntersection(s)<<endl;
    return 0;
}
accuracy: 1
time_ms: 80
memory_kb: 20216
final_rank: 15

code_snippet: // #define ENABLE_TUPLE_OPS_
#define DISABLE_PRAGMA_
#ifndef DISABLE_PRAGMA_
#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
#endif

#include <bits/stdc++.h>
#ifdef __GNUG__
// #include <bits/extc++.h>
#endif


template <class Tp>
using pi = std::pair<Tp, Tp>;
template <class Tp>
using pi3 = std::tuple<Tp, Tp, Tp>;
template <class Tp>
using pi4 = std::tuple<Tp, Tp, Tp, Tp>;
template <class Tp>
using vc = std::vector<Tp>;
template <class Tp>
using vvc = std::vector<std::vector<Tp>>;
template <class Tp>
using pq = std::priority_queue<Tp>;
template <class Tp>
using pqg = std::priority_queue<Tp, std::vector<Tp>, std::greater<Tp>>;
template <class Tp>
using hset = std::unordered_set<Tp>;
template <class Key, class Tp, class Hash = std::hash<Key>>
using hmap = std::unordered_map<Key, Tp, Hash>;


using i32 = int32_t;
using u32 = uint32_t;
using i64 = int64_t;
using u64 = uint64_t;
using i128 = __int128_t;
using u128 = __uint128_t;

using compi = std::complex<int>;
using compi64 = std::complex<i64>;
using compd = std::complex<double>;
using pii = pi<int>;
using pii64 = pi<i64>;
using pi3i = pi3<int>;
using pi3i64 = pi3<i64>;
using pi4i = pi4<int>;
using pi4i64 = pi4<i64>;


#define for_(i, l, r, vars...) for (decltype(l + r) i = (l), i##end = (r), ##vars; i <= i##end; ++i)
#define for_step_(i, l, r, s, vars...) for (decltype(l + r) i = (l), i##end = (r), ##vars; i <= i##end; i += s)
#define rfor_(i, r, l, vars...) for (make_signed_t<decltype(r - l)> i = (r), i##end = (l), ##vars; i >= i##end; --i)
#define rfor_step_(i, r, l, s, vars...) for (make_signed_t<decltype(r - l)> i = (r), i##end = (l), ##vars; i >= i##end; i -= s)
#define foreach_val_(i, container) for (auto i : (container))
#define foreach_ref_(i, container) for (auto &i : (container))
#define foreach_cref_(i, container) for (const auto &i : (container))
#define foreach_rref_(i, container) for (auto &&i : (container))
#define foreach_binding_(container, vars...) for (auto &&[vars] : container)
#define foreach_iter_(it, container) for (auto it = (container).begin(); it != (container).end(); ++it)
#define foreach_iter_range_(it, container, l, r) for (auto it = (container).begin() + (l); it != (container).begin() + (r); ++it)
#define foreach_riter_(it, container) for (auto it = (container).rbegin(); it != (container).rend(); ++it)
#define foreach_riter_range_(it, container, l, r) for (auto it = (container).rbegin() + (l); it != (container).rbegin() + (r); ++it)
#define ins_(a) std::inserter((a), (a).begin())
#define all_(a) (a).begin(), (a).end()
#define rall_(a) (a).rbegin(), (a).rend()
#define range_(a, l, r) ((a).begin() + (l)), ((a).begin() + (r))
#define rrange_(a, l, r) ((a).rbegin() + (l)), ((a).rbegin() + (r))
#define set_nul_(a) memset(a, 0, sizeof(a))
#define set_inf_(a) memset(a, 0x3f, sizeof(a))
#define set_nul_n_(a, n) memset(a, 0, sizeof(*(a)) * (n))
#define set_inf_n_(a, n) memset(a, 0x3f, sizeof(*(a)) * (n))
#define run_exec_(expressions, post_process) \
    {                                        \
        expressions;                         \
        post_process;                        \
    }
#define run_exit_(expressions) run_exec_(expressions, exit(0))
#define run_return_(expressions, val) run_exec_(expressions, return val)
#define run_return_void_(expressions) run_exec_(expressions, return )
#define run_break_(expressions) run_exec_(expressions, break)
#define run_continue_(expressions) run_exec_(expressions, continue)
#define read_var_(type, name) \
    type name;                \
    std::cin >> name
#define read_container_(type, name, size) \
    type name(size);                      \
    foreach_ref_(i, name) std::cin >> i


template <class Tp>
constexpr auto chkmin(Tp &a, Tp b) -> bool { return b < a ? a = b, true : false; };
template <class Tp>
constexpr auto chkmax(Tp &a, Tp b) -> bool { return a < b ? a = b, true : false; };
template <class Tp, class Pred>
inline Tp binary_search(Pred check, Tp ok, Tp ng) {
    assert(check(ok));
    while (std::abs(ok - ng) > 1) {
        Tp x = (ng + ok) / 2;
        (check(x) ? ok : ng) = x;
    }
    return ok;
}
template <class Tp, class Pred, std::enable_if_t<std::is_floating_point_v<Tp>> * = nullptr>
inline Tp binary_search_real(Pred check, Tp ok, Tp ng, Tp eps) {
    assert(check(ok));
    while (std::abs(ok - ng) > eps) {
        Tp x = (ng + ok) / 2;
        (check(x) ? ok : ng) = x;
    }
    return (ng + ok) / 2;
}
template <class Tp>
inline auto discretization(Tp &var) -> Tp {
    Tp d__(var);
    std::sort(d__.begin(), d__.end());
    d__.erase(std::unique(d__.begin(), d__.end()), d__.end());
    for (auto &i : var) i = std::distance(d__.begin(), std::lower_bound(d__.begin(), d__.end(), i));
    return d__;
};
template <class Tp>
constexpr auto ispow2(Tp i) -> bool { return i && (i & -i) == i; }

#ifdef ENABLE_TUPLE_OPS_

// <https://tifa-233.xyz/archives/draft-019/>
#define TPL_SIZE_(Tuple) std::tuple_size_v<std::remove_reference_t<Tuple>>

namespace tuple_detail_ {
template <std::size_t Begin, class Tuple, std::size_t... Is>
constexpr auto subtuple_impl_(Tuple &&t, std::index_sequence<Is...>) { return std::make_tuple(std::get<Is + Begin>(t)...); }
template <class Tuple, class BinOp, std::size_t... Is>
constexpr auto apply2_impl_(BinOp &&f, Tuple &&lhs, Tuple &&rhs, std::index_sequence<Is...>) { return std::make_tuple(std::forward<BinOp>(f)(std::get<Is>(lhs), std::get<Is>(rhs))...); }
}  // namespace tuple_detail_


template <std::size_t Begin, std::size_t Len, class Tuple>
constexpr auto subtuple(Tuple &&t) {
    static_assert(Begin <= TPL_SIZE_(Tuple) && Len <= TPL_SIZE_(Tuple) && Begin + Len <= TPL_SIZE_(Tuple), "Out of range");
    return tuple_detail_::subtuple_impl_<Begin>(t, std::make_index_sequence<Len>());
}

template <std::size_t Pos, class Tp, class Tuple>
constexpr auto tuple_push(Tp &&v, Tuple &&t) {
    static_assert(TPL_SIZE_(Tuple) > 0, "Pop from empty tuple");
    return std::tuple_cat(subtuple<0, Pos>(t), std::make_tuple(v), subtuple<Pos, TPL_SIZE_(Tuple) - Pos>(t));
}
template <class Tp, class Tuple>
constexpr auto tuple_push_front(Tp &&v, Tuple &&t) { return tuple_push<0>(v, t); }
template <class Tp, class Tuple>
constexpr auto tuple_push_back(Tp &&v, Tuple &&t) { return tuple_push<TPL_SIZE_(Tuple)>(v, t); }


template <std::size_t Pos, class Tuple>
constexpr auto tuple_pop(Tuple &&t) {
    static_assert(TPL_SIZE_(Tuple) > 0, "Pop from empty tuple");
    return std::tuple_cat(subtuple<0, Pos>(t), subtuple<Pos + 1, TPL_SIZE_(Tuple) - Pos - 1>(t));
}
template <class Tuple>
constexpr auto tuple_pop_front(Tuple &&t) { return tuple_pop<0>(t); }
template <class Tuple>
constexpr auto tuple_pop_back(Tuple &&t) { return tuple_pop<TPL_SIZE_(Tuple) - 1>(t); }

template <class Tuple, class BinOp>
constexpr auto apply2(BinOp &&f, Tuple &&lhs, Tuple &&rhs) { return tuple_detail_::apply2_impl_(f, lhs, rhs, std::make_index_sequence<TPL_SIZE_(Tuple)>()); }

#define OO_PT_(op)                                                                                                                                 \
    template <class Tp, class Up>                                                                                                                  \
    constexpr auto operator op(std::pair<Tp, Up> lhs, const std::pair<Tp, Up> &rhs) { return {lhs.first op rhs.first, lhs.second op rhs.second}; } \
    template <class... Ts>                                                                                                                         \
    constexpr auto operator op(std::tuple<Ts...> const &lhs, std::tuple<Ts...> const &rhs) {                                                       \
        return apply2([](auto &&l, auto &&r) { return l op r; }, lhs, rhs);                                                                        \
    }
#define OO_PTEQ_(op)                                                                                    \
    OO_PT_(op)                                                                                          \
    template <class Tp, class Up>                                                                       \
    constexpr std::pair<Tp, Up> &operator op##=(std::pair<Tp, Up> &lhs, const std::pair<Tp, Up> &rhs) { \
        lhs.first op## = rhs.first;                                                                     \
        lhs.second op## = rhs.second;                                                                   \
        return lhs;                                                                                     \
    }                                                                                                   \
    template <class... Ts>                                                                              \
    constexpr auto operator op##=(std::tuple<Ts...> &lhs, const std::tuple<Ts...> &rhs) { return lhs = lhs op rhs; }

OO_PTEQ_(+)
OO_PTEQ_(-)
OO_PTEQ_(*)
OO_PTEQ_(/)
OO_PTEQ_(%)
OO_PTEQ_(&)
OO_PTEQ_(|)
OO_PTEQ_(^)
OO_PTEQ_(<<)
OO_PTEQ_(>>)
OO_PT_(==)
OO_PT_(!=)
OO_PT_(<)
OO_PT_(<=)
OO_PT_(>)
OO_PT_(>=)

#undef OO_PT_
#undef TPL_SIZE_


template <class Tp, class Up>
std::istream &operator>>(std::istream &is, std::pair<Tp, Up> &p) { return is >> p.first >> p.second; }
template <class Tp, class Up>
std::ostream &operator<<(std::ostream &os, const std::pair<Tp, Up> &p) {
#ifdef LOCAL_
    if (&os == &std::cerr)
        return os << '<' << p.first << ", " << p.second << '>';
    else
#endif
        return os << p.first << ' ' << p.second;
}

template <typename... Ts>
std::istream &operator>>(std::istream &is, std::tuple<Ts...> &p) {
    std::apply([&](Ts &...targs) { ((is >> targs), ...); }, p);
    return is;
}
template <typename... Ts>
std::ostream &operator<<(std::ostream &os, const std::tuple<Ts...> &p) {
    std::apply(
        [&](Ts const &...targs) {
            std::size_t n{0};
#ifdef LOCAL_
            if (&os == &std::cerr) os << '(';
            if (&os == &std::cerr)
                ((os << targs << (++n != sizeof...(Ts) ? ", " : "")), ...);
            else
#endif
                ((os << targs << (++n != sizeof...(Ts) ? " " : "")), ...);
#ifdef LOCAL_
            if (&os == &std::cerr) os << ')';
#endif
        },
        p);
    return os;
}

#endif

template <class Ct, std::enable_if_t<std::is_same_v<decltype(std::declval<Ct>().begin()), typename Ct::iterator> && std::is_same_v<decltype(std::declval<Ct>().end()), typename Ct::iterator>> * = nullptr>
std::ostream &operator<<(std::ostream &os, const Ct &x) {
#ifdef LOCAL_
    if (&os == &std::cerr) os << '[';
    if (&os == &std::cerr)
        for (auto it = x.begin(); it != x.end() - 1; ++it) os << *it << ", ";
    else
#endif
        for (auto it = x.begin(); it != x.end() - 1; ++it) os << *it << ' ';
    os << x.back();
#ifdef LOCAL_
    if (&os == &std::cerr) os << ']';
#endif
    return os;
}


template <class Tp>
inline void debug(Tp x) {
#ifdef LOCAL_
    std::cerr << x << std::endl;
#endif
}
template <class Tp, class... Ts>
inline void debug(Tp x, Ts... args) {
#ifdef LOCAL_
    std::cerr << x << ' ';
    debug(args...);
#endif
}
#define debug_line_ (std::cerr << __LINE__ << ' ' << __FUNCTION__ << std::endl)
#define debug_withname_(var) debug(#var, var)


const u32 OFFSET = 5;
const u32 N = 5e5 + OFFSET;
const u32 M = 2e5 + OFFSET;
const u32 K = 21;
const u32 MOD = 1e9 + 7;
const double EPS = 1e-6;
const i32 INF = 0x3f3f3f3f;
const i64 INF64 = 0x3f3f3f3f3f3f3f3f;
const double PI = acos(-1.0);
const pii DIR4[4] = {{-1, 0}, {0, -1}, {0, 1}, {1, 0}};
const pii DIR8[8] = {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}};
const std::string RES_YN[2] = {"NO", "YES"};
const std::string RES_Yn[2] = {"No", "Yes"};
const std::string RES_yn[2] = {"no", "yes"};
const std::string RES_POSS[2] = {"IMPOSSIBLE", "POSSIBLE"};
const std::string RES_Poss[2] = {"Impossible", "Possible"};
const std::string RES_poss[2] = {"impossible", "possible"};
// const int64_t EXP10[10] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
// const int64_t FACT[11] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800};

template <size_t N_>
constexpr int64_t EXP10_impl_() { return EXP10_impl_<N_ - 1>() * 10; }
template <>
constexpr int64_t EXP10_impl_<0>() { return 1; }
template <size_t N_>
constexpr int64_t EXP10 = EXP10_impl_<N_>();

template <size_t N_>
constexpr int64_t FACT10_impl_() { return FACT10_impl_<N_ - 1>() * N_; }
template <>
constexpr int64_t FACT10_impl_<0>() { return 1; }
template <size_t N_>
constexpr int64_t FACT = FACT10_impl_<N_>();


using namespace std;
const auto STATIC__ = []() {
    return 0;
}();

// #define MULTI_CASES
inline auto solve([[maybe_unused]] int t_ = 0) -> void {
    vc<pi4i> vp4;
    read_var_(int, n);
    for_(i, 1, n, ax, ay, bx, by) {
        cin >> ax >> ay >> bx >> by;
        if (ax > bx) swap(ax, bx);
        if (ay > by) swap(ay, by);
        if (ax == bx) run_continue_(vp4.emplace_back(ax, 0, ay, by));
        vp4.emplace_back(ax, -1, ay, 0);
        vp4.emplace_back(bx, 1, by, 0);
    }
    sort(all_(vp4));
    i64 ans = 0;
    set<int> s;
    for (auto &&x : vp4) {
        if (get<1>(x) == -1) run_continue_(s.insert(get<2>(x)));
        if (get<1>(x) == 1) run_continue_(s.erase(get<2>(x)));
        ans += distance(s.lower_bound(get<2>(x)), s.upper_bound(get<3>(x)));
    }
    cout << ans << '\n';
}

int main() {
#ifdef LOCAL_
    auto CLOCK_ST_ = std::chrono::high_resolution_clock::now();
#endif
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int i_ = STATIC__;
    // cout << fixed << setprecision(12);
    std::cerr << boolalpha << fixed << setprecision(12);

#ifdef MULTI_CASES
    int t_ = 0;
    std::cin >> t_;
    for (i_ = 1; i_ <= t_; ++i_)
#endif
        debug("Case", i_), solve(i_);
#ifdef LOCAL_
    auto CLOCK_ED_ = std::chrono::high_resolution_clock::now();
    std::clog << "\n---\n"
              << "Time used: " << std::chrono::duration_cast<std::chrono::nanoseconds>(CLOCK_ED_ - CLOCK_ST_).count() * 1e-6l << " ms" << std::endl;
#endif
    return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 9860
final_rank: 1

code_snippet: #include <bits/stdc++.h>
#define init(x) memset (x,0,sizeof (x))
#define ll long long
#define ull unsigned long long
#define INF 0x3f3f3f3f
#define pii pair <int,int>
using namespace std;
const int MAX = 3e5 + 5;
const int MOD = 1e9 + 7;
inline int read ();
struct point {int x,y;};
struct seg
{
    point A,B;int op;
    seg (point A,point B,int op) : A (A),B (B),op (op) {}
    bool operator < (const seg &p)
    {
        if (A.y != p.A.y) return A.y < p.A.y;
        else return op != p.op ? op < p.op : A.x < p.A.x;
    }
};
int n;ll ans,tree[MAX << 2];
void modify (int cur,int l,int r,int x,int v)
{
    if (l == r) {tree[cur] += v;return ;}
    int mid = (l + r) >> 1;
    if (x <= mid) modify (cur << 1,l,mid,x,v);
    else modify (cur << 1 | 1,mid + 1,r,x,v);
    tree[cur] = tree[cur << 1] + tree[cur << 1 | 1];
}
ll query (int cur,int l,int r,int x,int y)
{
    if (x <= l && y >= r) return tree[cur];
    int mid = (l + r) >> 1;ll res = 0;
    if (x <= mid) res += query (cur << 1,l,mid,x,y);
    if (y > mid) res += query (cur << 1 | 1,mid + 1,r,x,y);
    return res;
}
int main ()
{
    n = read ();
    vector <int> p;vector <seg> v;
    for (int i = 1;i <= n;++i)
    {
        point A,B;
        A.x = read (),A.y = read ();B.x = read (),B.y = read ();
        if (A.x == B.x)
        {
            if (A.y > B.y) swap (A,B);
            p.push_back (A.x);
            v.push_back ({A,A,1});
            v.push_back ({B,B,3});
        }
        else
        {
            if (A.x > B.x) swap (A,B);
            p.push_back (A.x);p.push_back (B.x);
            v.push_back ({A,B,2});
        }
    }
    sort (p.begin (),p.end ());
    p.erase (unique (p.begin (),p.end ()),p.end ());
    sort (v.begin (),v.end ());
    for (auto [A,B,op] : v)
    {
        int x = lower_bound (p.begin (),p.end (),A.x) - p.begin () + 1;
        int y = lower_bound (p.begin (),p.end (),B.x) - p.begin () + 1;
        if (A.x == B.x) modify (1,1,p.size (),x,op == 1 ? 1 : -1);
        else ans += query (1,1,p.size (),x,y);
    }
    printf ("%lld\n",ans);
    return 0;
}
inline int read ()
{
    int s = 0;int f = 1;
    char ch = getchar ();
    while ((ch < '0' || ch > '9') && ch != EOF)
    {
        if (ch == '-') f = -1;
        ch = getchar ();
    }
    while (ch >= '0' && ch <= '9')
    {
        s = s * 10 + ch - '0';
        ch = getchar ();
    }
    return s * f;
}
accuracy: 1
time_ms: 50
memory_kb: 12188
final_rank: 2

code_snippet: #include <bits/stdc++.h>
using namespace std;

template<class S, class T> inline bool chmax(S &a, T b) { return (a < b ? a = b, 1 : 0); }
template<class S, class T> inline bool chmin(S &a, T b) { return (a > b ? a = b, 1 : 0); }

using pint = pair<int, int>;
using pll = pair<long long, long long>;
using tint = array<int, 3>;
using tll = array<long long, 3>;
using fint = array<int, 4>;
using fll = array<long long, 4>;
using vll = vector<long long>;
using ll = long long;
using u32 = unsigned int;
using u64 = unsigned long long;
using int128 = __int128;
using u128 = unsigned __int128;
template <class T>
using min_priority_queue = priority_queue<T, vector<T>, greater<T>>;

#define REP(i, a) for (long long i = 0; i < (long long)(a); i++)
#define REP2(i, a, b) for (long long i = a; i < (long long)(b); i++)
#define RREP(i, a) for (long long i = (a)-1; i >= (long long)(0); --i)
#define RREP2(i, a, b) for (long long i = (b)-1; i >= (long long)(a); --i)
#define EB emplace_back
#define PB push_back
#define MP make_pair
#define MT make_tuple
#define FI first
#define SE second
#define ALL(x) x.begin(), x.end()
#define COUT(x) cout << #x << " = " << (x) << " (L" << __LINE__ << ")" << endl

// debug stream
template<class T1, class T2> ostream& operator << (ostream &s, pair<T1,T2> P)
{ return s << '<' << P.first << ", " << P.second << '>'; }
template<class T> ostream& operator << (ostream &s, vector<T> P)
{ for (int i = 0; i < P.size(); ++i) { if (i > 0) { s << " "; } s << P[i]; } return s; }
template<class T> ostream& operator << (ostream &s, deque<T> P)
{ for (int i = 0; i < P.size(); ++i) { if (i > 0) { s << " "; } s << P[i]; } return s; }
template<class T> ostream& operator << (ostream &s, vector<vector<T> > P)
{ for (int i = 0; i < P.size(); ++i) { s << endl << P[i]; } return s << endl; }
template<class T> ostream& operator << (ostream &s, set<T> P)
{ for (auto it : P) { s << "<" << it << "> "; } return s; }
template<class T> ostream& operator << (ostream &s, multiset<T> P)
{ for (auto it : P) { s << "<" << it << "> "; } return s; }
template<class T1, class T2> ostream& operator << (ostream &s, map<T1,T2> P)
{ for (auto it : P) { s << "<" << it.first << "->" << it.second << "> "; } return s; }


//------------------------------//
// 幾何の基本要素 (点, 線分, 円)
//------------------------------//

// basic settings
long double EPS = 1e-12;  // to be set appropriately
constexpr long double PI = 3.141592653589793238462643383279502884L;
long double torad(long double deg) {return (long double)(deg) * PI / 180;}
long double todeg(long double ang) {return ang * 180 / PI;}

// Point or Vector
template<class DD> struct Point {
    // inner value
    DD x, y;
    
    // constructor
    constexpr Point() : x(0), y(0) {}
    constexpr Point(DD x, DD y) : x(x), y(y) {}
    
    // various functions
    constexpr Point conj() const {return Point(x, -y);}
    constexpr DD dot(const Point &r) const {return x * r.x + y * r.y;}
    constexpr DD cross(const Point &r) const {return x * r.y - y * r.x;}
    constexpr DD norm() const {return dot(*this);}
    constexpr long double abs() const {return sqrt(norm());}
    constexpr long double arg() const {
        if (this->eq(Point(0, 0))) return 0L;
        else if (x < -EPS && this->eq(Point(x, 0))) return PI;
        else return atan2((long double)(y), (long double)(x));
    }
    constexpr bool eq(const Point &r) const {return (*this - r).abs() <= EPS;}
    constexpr Point rot90() const {return Point(-y, x);}
    constexpr Point rot(long double ang) const {
        return Point(cos(ang) * x - sin(ang) * y, sin(ang) * x + cos(ang) * y);
    }
    
    // arithmetic operators
    constexpr Point operator - () const {return Point(-x, -y);}
    constexpr Point operator + (const Point &r) const {return Point(*this) += r;}
    constexpr Point operator - (const Point &r) const {return Point(*this) -= r;}
    constexpr Point operator * (const Point &r) const {return Point(*this) *= r;}
    constexpr Point operator / (const Point &r) const {return Point(*this) /= r;}
    constexpr Point operator * (DD r) const {return Point(*this) *= r;}
    constexpr Point operator / (DD r) const {return Point(*this) /= r;}
    constexpr Point& operator += (const Point &r) {
        x += r.x, y += r.y;
        return *this;
    }
    constexpr Point& operator -= (const Point &r) {
        x -= r.x, y -= r.y;
        return *this;
    }
    constexpr Point& operator *= (const Point &r) {
        DD tx = x, ty = y;
        x = tx * r.x - ty * r.y;
        y = tx * r.y + ty * r.x;
        return *this;
    }
    constexpr Point& operator /= (const Point &r) {
        return *this *= r.conj() / r.norm();
    }
    constexpr Point& operator *= (DD r) {
        x *= r, y *= r;
        return *this;
    }
    constexpr Point& operator /= (DD r) {
        x /= r, y /= r;
        return *this;
    }

    // friend functions
    friend ostream& operator << (ostream &s, const Point &p) {
        return s << '(' << p.x << ", " << p.y << ')';
    }
    friend constexpr Point conj(const Point &p) {return p.conj();}
    friend constexpr DD dot(const Point &p, const Point &q) {return p.dot(q);}
    friend constexpr DD cross(const Point &p, const Point &q) {return p.cross(q);}
    friend constexpr DD norm(const Point &p) {return p.norm();}
    friend constexpr long double abs(const Point &p) {return p.abs();}
    friend constexpr long double arg(const Point &p) {return p.arg();}
    friend constexpr bool eq(const Point &p, const Point &q) {return p.eq(q);}
    friend constexpr Point rot90(const Point &p) {return p.rot90();}
    friend constexpr Point rot(const Point &p, long long ang) {return p.rot(ang);}
};

// necessary for some functions
template<class DD> constexpr bool operator < (const Point<DD> &p, const Point<DD> &q) {
    return (abs(p.x - q.x) > EPS ? p.x < q.x : p.y < q.y);
}

// Line
template<class DD> struct Line : vector<Point<DD>> {
    Line(Point<DD> a = Point<DD>(0, 0), Point<DD> b = Point<DD>(0, 0)) {
        this->push_back(a);
        this->push_back(b);
    }
    friend ostream& operator << (ostream &s, const Line<DD> &l) {
        return s << '{' << l[0] << ", " << l[1] << '}';
    }
};

// Circle
template<class DD> struct Circle : Point<DD> {
    DD r;
    Circle(Point<DD> p = Point<DD>(0, 0), DD r = 0) : Point<DD>(p), r(r) {}
    friend ostream& operator << (ostream &s, const Circle<DD> &c) {
        return s << '(' << c.x << ", " << c.y << ", " << c.r << ')';
    }
};


//------------------------------//
// 点や線分の位置関係
//------------------------------//

// arg sort
// by defining comparison
template<class DD> void arg_sort(vector<Point<DD>> &v) {
    auto sign = [&](const Point<DD> &p) -> int {
        if (abs(p.x) <= EPS && abs(p.y) <= EPS) return 0;
        else if (p.y < -EPS || (abs(p.y) <= EPS && p.x > EPS)) return -1;
        else return 1;
    };
    auto cmp = [&](const Point<DD> &p, const Point<DD> &q) -> bool {
        if (sign(p) != sign(q)) return sign(p) < sign(q);
        return (abs(cross(p, q)) > EPS ? cross(p, q) > EPS : norm(p) < norm(q));
    };
    sort(v.begin(), v.end(), cmp);
}
// by calculating arg directly
template<class DD> void arg_sort_direct(vector<Point<DD>> &v) {
    auto cmp = [&](const Point<DD> &p, const Point<DD> &q) -> bool {
        return (abs(arg(p) - arg(q)) > EPS ? arg(p) < arg(q) : norm(p) < norm(q));
    };
    sort(v.begin(), v.end(), cmp);
}

// 粗
// 1：a-bから見てcは左側(反時計回り)、-1：a-bから見てcは右側(時計回り)、0：一直線上
template<class DD> int simple_ccw
 (const Point<DD> &a, const Point<DD> &b, const Point<DD> &c) {
    if (cross(b-a, c-a) > EPS) return 1;
    if (cross(b-a, c-a) < -EPS) return -1;
    return 0;
}

// 精
// 1：a-bから見てcは左側(反時計回り)、-1：a-bから見てcは右側(時計回り)
// 2：c-a-bの順に一直線上、-2：a-b-cの順に一直線上、0：a-c-bの順に一直線上
template<class DD> int ccw
 (const Point<DD> &a, const Point<DD> &b, const Point<DD> &c) {
    if (cross(b-a, c-a) > EPS) return 1;
    if (cross(b-a, c-a) < -EPS) return -1;
    if (dot(b-a, c-a) < -EPS) return 2;
    if (norm(b-a) < norm(c-a) - EPS) return -2;
    return 0;
}

// 点と三角形の包含関係(辺上については判定していない)
template<class DD> bool is_contain
 (const Point<DD> &p, const Point<DD> &a, const Point<DD> &b, const Point<DD> &c) {
    int r1 = simple_ccw(p, b, c), r2 = simple_ccw(p, c, a), r3 = simple_ccw(p, a, b);
    if (r1 == 1 && r2 == 1 && r3 == 1) return true;
    if (r1 == -1 && r2 == -1 && r3 == -1) return true;
    return false;
}


//------------------------------//
// 線分の交差判定や距離計算
//------------------------------//

template<class DD> int ccw_for_dis
 (const Point<DD> &a, const Point<DD> &b, const Point<DD> &c) {
    if (cross(b-a, c-a) > EPS) return 1;
    if (cross(b-a, c-a) < -EPS) return -1;
    if (dot(b-a, c-a) < -EPS) return 2;
    if (norm(b-a) < norm(c-a) - EPS) return -2;
    return 0;
}
template<class DD> Point<DD> proj(const Point<DD> &p, const Line<DD> &l) {
    DD t = dot(p - l[0], l[1] - l[0]) / norm(l[1] - l[0]);
    return l[0] + (l[1] - l[0]) * t;
}
template<class DD> Point<DD> refl(const Point<DD> &p, const Line<DD> &l) {
    return p + (proj(p, l) - p) * 2;
}
template<class DD> bool is_inter_PL(const Point<DD> &p, const Line<DD> &l) {
    return (abs(p - proj(p, l)) < EPS);
}
template<class DD> bool is_inter_PS(const Point<DD> &p, const Line<DD> &s) {
    return (ccw_for_dis(s[0], s[1], p) == 0);
}
template<class DD> bool is_inter_LL(const Line<DD> &l, const Line<DD> &m) {
    return (abs(cross(l[1] - l[0], m[1] - m[0])) > EPS ||
            abs(cross(l[1] - l[0], m[0] - l[0])) < EPS);
}
template<class DD> bool is_inter_SS(const Line<DD> &s, const Line<DD> &t) {
    if (eq(s[0], s[1])) return is_inter_PS(s[0], t);
    if (eq(t[0], t[1])) return is_inter_PS(t[0], s);
    return (ccw_for_dis(s[0], s[1], t[0]) * ccw_for_dis(s[0], s[1], t[1]) <= 0 &&
            ccw_for_dis(t[0], t[1], s[0]) * ccw_for_dis(t[0], t[1], s[1]) <= 0);
}
template<class DD> DD distance_PL(const Point<DD> &p, const Line<DD> &l) {
    return abs(p - proj(p, l));
}
template<class DD> DD distance_PS(const Point<DD> &p, const Line<DD> &s) {
    if (dot(p - s[0], s[1] - s[0]) < 0) return abs(p - s[0]);
    else if (dot(p - s[1], s[0] - s[1]) < 0) return abs(p - s[1]);
    else return abs(p - proj(p, s));
}
template<class DD> DD distance_LL(const Line<DD> &l, const Line<DD> &m) {
    if (is_inter_LL(l, m)) return 0;
    else return distance_PL(m[0], l);
}
template<class DD> DD distance_SS(const Line<DD> &s, const Line<DD> &t) {
    if (is_inter_SS(s, t)) return 0;
    else return min(min(distance_PS(s[0], t), distance_PS(s[1], t)),
                    min(distance_PS(t[0], s), distance_PS(t[1], s)));
}


//------------------------------//
// 円や直線の交点
//------------------------------//

template<class DD> Point<DD> proj_for_crosspoint(const Point<DD> &p, const Line<DD> &l) {
    DD t = dot(p - l[0], l[1] - l[0]) / norm(l[1] - l[0]);
    return l[0] + (l[1] - l[0]) * t;
}
template<class DD> vector<Point<DD>> crosspoint(const Line<DD> &l, const Line<DD> &m) {
    vector<Point<DD>> res;
    DD d = cross(m[1] - m[0], l[1] - l[0]);
    if (abs(d) < EPS) return vector<Point<DD>>();
    res.push_back(l[0] + (l[1] - l[0]) * cross(m[1] - m[0], m[1] - l[0]) / d);
    return res;
}
template<class DD> vector<Point<DD>> crosspoint_SS(const Line<DD> &l, const Line<DD> &m) {
    if (is_inter_SS(l, m)) return crosspoint(l, m);
    else return vector<Point<DD>>();
}
template<class DD> vector<Point<DD>> crosspoint(const Circle<DD> &e, const Circle<DD> &f) {
    vector<Point<DD>> res;
    DD d = abs(e - f);
    if (d < EPS) return vector<Point<DD>>();
    if (d > e.r + f.r + EPS) return vector<Point<DD>>();
    if (d < abs(e.r - f.r) - EPS) return vector<Point<DD>>();
    DD rcos = (d * d + e.r * e.r - f.r * f.r) / (2.0 * d), rsin;
    if (e.r - abs(rcos) < EPS) rsin = 0;
    else rsin = sqrt(e.r * e.r - rcos * rcos);
    Point<DD> dir = (f - e) / d;
    Point<DD> p1 = e + dir * Point(rcos, rsin);
    Point<DD> p2 = e + dir * Point(rcos, -rsin);
    res.push_back(p1);
    if (!eq(p1, p2)) res.push_back(p2);
    return res;
}
template<class DD> vector<Point<DD>> crosspoint(const Circle<DD> &e, const Line<DD> &l) {
    vector<Point<DD>> res;
    Point<DD> p = proj_for_crosspoint(e, l);
    DD rcos = abs(e - p), rsin;
    if (rcos > e.r + EPS) return vector<Point<DD>>();
    else if (e.r - rcos < EPS) rsin = 0;
    else rsin = sqrt(e.r * e.r - rcos * rcos);
    Point<DD> dir = (l[1] - l[0]) / abs(l[1] - l[0]);
    Point<DD> p1 = p + dir * rsin;
    Point<DD> p2 = p - dir * rsin;
    res.push_back(p1);
    if (!eq(p1, p2)) res.push_back(p2);
    return res;
}

template<class Abel> struct FastMultiSetByBIT {
    int topbit(int x) const { return (x == 0 ? -1 : 31 - __builtin_clz(x)); }
    int lowbit(int x) const { return (x == 0 ? -1 : __builtin_ctz(x)); }
    int lim;
    Abel IDENTITY;
    vector<Abel> dat;
    
    // [0, n)
    FastMultiSetByBIT(int n, Abel identity = 0)
    : lim(n), IDENTITY(identity), dat(n, identity) { }
    void init(int n, Abel identity = 0) {
        lim = n;
        IDENTITY = identity;
        dat.assign(n, IDENTITY);
    }
    
    // p is 0-indexed
    void add(int p, Abel x) {
        if (p < 0) p = 0;
        for (int i = p; i < (int)dat.size(); i |= i + 1)
            dat[i] = dat[i] + x;
    }
    
    // [0, p), p is 0-indexed
    Abel sum(int p) const {
        if (p > lim) p = lim;
        Abel res = IDENTITY;
        for (int i = p - 1; i >= 0; i = (i & (i + 1)) - 1)
            res = res + dat[i];
        return res;
    }
    
    // [l, r), l and r are 0-indexed
    Abel sum(int l, int r) const {
        return sum(r) - sum(l);
    }
    
    // insert, erase, count, min, max
    void insert(int x) { add(x, 1); }
    void erase(int x) { if (count(x)) add(x, -1); }
    Abel count(int x) const { return sum(x, x + 1); }
    Abel count(int l, int r) const { return sum(l, r); }
    Abel size() const { return sum(lim); }
    bool operator [] (int x) const { return count(x); }
    int get_min() const { return next(); }
    int get_max() const { return prev(); }

    // get max r s.t. check(sum(l, r)) = True (0-indexed), O(log N)
    // check(IDENTITY) must be True
    int max_right(const function<bool(Abel)> check, int l = 0) const {
        if (l >= lim) return lim;
        assert(check(IDENTITY));
        Abel s = IDENTITY;
        int k = 0;
        while (true) {
            if (l % 2 == 1) s = s - dat[l - 1], --l;
            if (l <= 0) {
                k = topbit(lim) + 1;
                break;
            }
            k = lowbit(l) - 1;
            if (l + (1 << k) > lim) break;
            if (!check(s + dat[l + (1 << k) - 1])) break;
            s = s - dat[l - 1];
            l -= l & -l;
        }
        while (k) {
            --k;
            if (l + (1 << k) - 1 < lim) {
                Abel ns = s + dat[l + (1 << k) - 1];
                if (check(ns)) {
                    l += (1 << k);
                    s = ns;
                }
            }
        }
        return l;
    }
    
    // get min l s.t. check(sum(l, r))  = True (0-indexed), O(log N)
    // check(IDENTITY) must be True
    int min_left(const function<bool(Abel)> check, int r = -1) const {
        if (r == -1) r = lim;
        if (r <= 0) return 0;
        assert(check(IDENTITY));
        Abel s = IDENTITY;
        int k = 0;
        while (r > 0 && check(s)) {
            s = s + dat[r - 1];
            k = lowbit(r);
            r -= r & -r;
        }
        if (check(s)) return 0;
        while (k) {
            --k;
            Abel ns = s - dat[r + (1 << k) - 1];
            if (!check(ns)) {
                r += (1 << k);
                s = ns;
            }
        }
        return r + 1;
    }
              
    // k-th number that is not less than l (k is 0-indexed)
    int get(Abel k, int l = 0) const {
        return max_right([&](Abel x) { return x <= k; }, l);
    }
    
    // next (including x)
    int next(int l = 0) const {
        if (l < 0) l = 0;
        if (l > lim) l = lim;
        return max_right([&](Abel x) { return x <= 0; }, l);
    }
    
    // prev (including x)
    int prev(int r) const {
        if (r > lim) r = lim;
        return min_left([&](Abel x) { return x <= 0; }, r + 1) - 1;
    }
    int prev() const {
        return prev(lim);
    }
    
    // debug
    friend ostream& operator << (ostream &s, const FastMultiSetByBIT &fs) {
        for (int x = fs.get_min(); x < fs.lim; x = fs.next(x + 1)) {
            s << x << " ";
        }
        return s;
    }
};


int main() {
    int N;
    cin >> N;

    const int IN = 0;
    const int GET = 1;
    const int OUT = 2;
    struct Event {
        int typ, xl, xr, y;
        Event() {}
        Event(int typ, int xl, int xr, int y) : typ(typ), xl(xl), xr(xr), y(y) {}
        constexpr bool operator < (const Event &rhs) const {
            return pint(y, typ) < pint(rhs.y, rhs.typ);
        };
    };

    vector<int> comp;
    vector<Event> evs;
    REP(i, N) {
        int x1, y1, x2, y2;
        cin >> x1 >> y1 >> x2 >> y2;
        if (x1 == x2) {
            evs.EB(Event(IN, x1, x2, min(y1, y2)));
            evs.EB(Event(OUT, x1, x2, max(y1, y2)));
        } else {
            evs.EB(Event(GET, min(x1, x2), max(x1, x2), y1));
        }
        comp.EB(x1), comp.EB(x2);
    }
    sort(evs.begin(), evs.end());
    sort(comp.begin(), comp.end());
    comp.erase(unique(comp.begin(), comp.end()), comp.end());

    FastMultiSetByBIT<int> sx(comp.size()+10);

    ll res = 0;
    for (auto [typ, xl, xr, y] : evs) {
        int l = lower_bound(comp.begin(), comp.end(), xl) - comp.begin() + 1; 
        int r = lower_bound(comp.begin(), comp.end(), xr) - comp.begin() + 1;
        if (typ == IN) sx.insert(l);
        else if (typ == OUT) sx.erase(l);
        else {
            ll add = sx.count(l, r+1);
            res += add;

            //COUT(comp); COUT(y); COUT(sx); COUT(l); COUT(r); COUT(add);
        }
    }
    cout << res << endl;
}
accuracy: 1
time_ms: 90
memory_kb: 10336
final_rank: 9

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for (i = 0; i < (int)(n); i++)
using ll = long long;

#define EPS (1e-10)
#define equals(a, b) (fabs((a) - (b)) < EPS)

enum
{
    COUNTER_CLOCKWISE = 1,
    CLOCKWISE = -1,
    ONLINE_BACK = 2,
    ONLINE_FRONT = -2,
    ON_SEGMENT = 0
};

enum
{
    IN = 2,
    ON = 1,
    OUT = 0
};

enum
{
    BOTTOM = 0,
    LEFT = 1,
    RIGHT = 2,
    TOP = 3
};

class Point
{
public:
    double x;
    double y;

    Point(double x = 0, double y = 0) : x(x), y(y) {}

    Point operator+(const Point p) const
    {
        return Point(x + p.x, y + p.y);
    }
    Point operator-(const Point p) const
    {
        return Point(x - p.x, y - p.y);
    }
    Point operator*(const double k) const
    {
        return Point(x * k, y * k);
    }
    Point operator/(const double k) const
    {
        return Point(x / k, y / k);
    }

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

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

class Circle
{
public:
    Point c;
    double r;
    Circle(Point c = Point(), double r = 0.0) : c(c), r(r) {}
};

struct Segment
{
    Point p1;
    Point p2;
};

typedef vector<Point> Polygon;

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

    bool operator<(const EndPoint &ep) const
    {
        if (p.y == ep.p.y)
        {
            return st < ep.st;
        }
        else
        {
            return p.y < ep.p.y;
        }
    }
};

double arg(Point p)
{
    return atan2(p.y, p.x);
}

Point polar(double a, double r)
{
    return Point(cos(r) * a, sin(r) * a);
}

double dot(Point a, Point b)
{
    return a.x * b.x + a.y * b.y;
}

double cross(Point a, Point b)
{
    return a.x * b.y - a.y * b.x;
}

bool isOrthogonal(Point a, Point b)
{
    return equals(dot(a, b), 0.0);
}

bool isOrthogonal(Point a1, Point a2, Point b1, Point b2)
{
    return isOrthogonal(a1 - a2, b1 - b2);
}

bool isOrthogonal(Segment s1, Segment s2)
{
    return equals(dot(s1.p2 - s1.p1, s2.p2 - s2.p1), 0.0);
}

bool isParallel(Point a, Point b)
{
    return equals(cross(a, b), 0.0);
}

bool isParallel(Point a1, Point a2, Point b1, Point b2)
{
    return isParallel(a1 - a2, b1 - b2);
}

bool isParallel(Segment s1, Segment s2)
{
    return equals(cross(s1.p2 - s1.p1, s2.p2 - s2.p1), 0.0);
}

Point project(Segment s, Point p)
{
    Point base = s.p2 - s.p1;
    double r = dot(p - s.p1, base) / base.norm();
    return s.p1 + base * r;
}

Point reflect(Segment s, Point p)
{
    return p + (project(s, p) - p) * 2;
}

int ccw(Point p0, Point p1, Point p2)
{
    Point a = p1 - p0;
    Point b = p2 - p0;
    if (cross(a, b) > EPS)
    {
        return COUNTER_CLOCKWISE;
    }
    if (cross(a, b) < -EPS)
    {
        return CLOCKWISE;
    }
    if (dot(a, b) < -EPS)
    {
        return ONLINE_BACK;
    }
    if (a.norm() < b.norm())
    {
        return ONLINE_FRONT;
    }
    return ON_SEGMENT;
}

bool intersect(Point p1, Point p2, Point p3, Point p4)
{
    return ccw(p1, p2, p3) * ccw(p1, p2, p4) <= 0 && ccw(p3, p4, p1) * ccw(p3, p4, p2) <= 0;
}

bool intersect(Segment s1, Segment s2)
{
    return intersect(s1.p1, s1.p2, s2.p1, s2.p2);
}

double getDistance(Point a, Point b)
{
    return (a - b).abs();
}

double getDistanceLP(Segment s, Point p)
{
    return abs(cross(s.p2 - s.p1, p - s.p1) / (s.p2 - s.p1).abs());
}

double getDistanceSP(Segment s, Point p)
{
    if (dot(s.p2 - s.p1, p - s.p1) < 0.0)
    {
        return getDistance(p, s.p1);
    }
    if (dot(s.p1 - s.p2, p - s.p2) < 0.0)
    {
        return getDistance(p, s.p2);
    }
    return getDistanceLP(s, p);
}

double getDistance(Segment s1, Segment s2)
{
    if (intersect(s1, s2))
    {
        return 0.0;
    }
    return min(min(getDistanceSP(s1, s2.p1), getDistanceSP(s1, s2.p2)), min(getDistanceSP(s2, s1.p1), getDistanceSP(s2, s1.p2)));
}

bool intersect(Circle c, Segment s)
{
    return getDistanceLP(s, c.c) <= c.r;
}

bool intersect(Circle c1, Circle c2)
{
    return getDistance(c1.c, c2.c) <= c1.r + c2.r;
}

Point getCrossPoint(Segment s1, Segment s2)
{
    Point base = s2.p2 - s2.p1;
    double d1 = abs(cross(base, s1.p1 - s2.p1));
    double d2 = abs(cross(base, s1.p2 - s2.p1));
    double t = d1 / (d1 + d2);
    return s1.p1 + (s1.p2 - s1.p1) * t;
}

pair<Point, Point> getCrossPoints(Circle c, Segment s)
{
    Point pr;
    Point e;
    double base;

    assert(intersect(c, s));
    pr = project(s, c.c);
    e = (s.p2 - s.p1) / (s.p2 - s.p1).abs();
    base = sqrt(c.r * c.r - (pr - c.c).norm());
    return {pr - e * base, pr + e * base};
}

pair<Point, Point> getCrossPoints(Circle c1, Circle c2)
{
    double d;
    double a;
    double t;

    assert(intersect(c1, c2));
    d = (c1.c - c2.c).abs();
    a = acos((c1.r * c1.r + d * d - c2.r * c2.r) / (2 * c1.r * d));
    t = arg(c2.c - c1.c);
    return {c1.c + polar(c1.r, t + a), c1.c + polar(c1.r, t - a)};
}

int contains(Polygon g, Point p)
{
    bool ans;
    Point a;
    Point b;
    int i;

    ans = false;
    rep(i, g.size())
    {
        a = g.at(i) - p;
        b = g.at((i + 1) % g.size()) - p;
        if (abs(cross(a, b)) < EPS && dot(a, b) < EPS)
        {
            return ON;
        }
        if (a.y > b.y)
        {
            swap(a, b);
        }
        if (a.y < EPS && EPS < b.y && cross(a, b) > EPS)
        {
            ans = !ans;
        }
    }
    if (ans)
    {
        return IN;
    }
    else
    {
        return OUT;
    }
}

Polygon andrewScan(Polygon s)
{
    Polygon u;
    Polygon l;
    int i;
    int n;

    if (s.size() < 3)
    {
        return s;
    }
    sort(s.begin(), s.end());
    u.push_back(s.at(0));
    u.push_back(s.at(1));
    l.push_back(s.at(s.size() - 1));
    l.push_back(s.at(s.size() - 2));

    for (i = 2; i < (int)s.size(); i++)
    {
        for (n = u.size(); n >= 2 && ccw(u.at(n - 2), u.at(n - 1), s.at(i)) != CLOCKWISE && ccw(u.at(n - 2), u.at(n - 1), s.at(i)) != ONLINE_FRONT; n--)
        {
            u.pop_back();
        }
        u.push_back(s.at(i));
    }

    for (i = s.size() - 3; i >= 0; i--)
    {
        for (n = l.size(); n >= 2 && ccw(l.at(n - 2), l.at(n - 1), s.at(i)) != CLOCKWISE && ccw(l.at(n - 2), l.at(n - 1), s.at(i)) != ONLINE_FRONT; n--)
        {
            l.pop_back();
        }
        l.push_back(s.at(i));
    }

    reverse(l.begin(), l.end());
    for (i = u.size() - 2; i >= 1; i--)
    {
        l.push_back(u.at(i));
    }
    return l;
}

int manhattanIntersection(vector<Segment> S)
{
    int i;
    vector<EndPoint> EP;
    set<int> BT;
    BT.insert(INT_MAX);
    int cnt;

    rep(i, S.size())
    {
        if (S.at(i).p1.y == S.at(i).p2.y)
        {
            if (S.at(i).p1.x > S.at(i).p2.x)
            {
                swap(S.at(i).p1, S.at(i).p2);
            }
        }
        else
        {
            if (S.at(i).p1.y > S.at(i).p2.y)
            {
                swap(S.at(i).p1, S.at(i).p2);
            }
        }

        if (S.at(i).p1.y == S.at(i).p2.y)
        {
            EP.push_back(EndPoint(S.at(i).p1, i, LEFT));
            EP.push_back(EndPoint(S.at(i).p2, i, RIGHT));
        }
        else
        {
            EP.push_back(EndPoint(S.at(i).p1, i, BOTTOM));
            EP.push_back(EndPoint(S.at(i).p2, i, TOP));
        }
    }
    sort(EP.begin(), EP.end());

    cnt = 0;
    rep(i, EP.size())
    {
        if (EP.at(i).st == TOP)
        {
            BT.erase(EP.at(i).p.x);
        }
        else if (EP.at(i).st == BOTTOM)
        {
            BT.insert(EP.at(i).p.x);
        }
        else if (EP.at(i).st == LEFT)
        {
            auto b = BT.lower_bound(S.at(EP.at(i).seg).p1.x);
            auto e = BT.upper_bound(S.at(EP.at(i).seg).p2.x);
            cnt += distance(b, e);
        }
    }
    return cnt;
}

int main()
{
    int n;
    int i;

    cin >> n;
    vector<Segment> S(n);
    rep(i, n)
    {
        cin >> S.at(i).p1.x >> S.at(i).p1.y >> S.at(i).p2.x >> S.at(i).p2.y;
    }
    cout << manhattanIntersection(S) << endl;

    return 0;
}
accuracy: 1
time_ms: 100
memory_kb: 17872
final_rank: 16

code_snippet: #include <bits/stdc++.h>
using namespace std;

const int BOTTOM = 0, LEFT = 1, RIGHT = 2, TOP = 3;

struct Point {
	int x, y;
	Point(int x = 0, int y = 0) : x(x), y(y) {}
	
};

struct Segment {
	Point p1, p2;
};

struct EndPoint {
	Point p;
	int seg, type;
	EndPoint() {}
	EndPoint(Point p, int seg, int type) : p(p), seg(seg), type(type) {}
	
	bool operator < (const EndPoint &ep) const {
		return p.y == ep.p.y ? type < ep.type : p.y < ep.p.y;
	}
};

EndPoint EP[2 * 100000];

int manhattanIntersection(vector<Segment> S) {
	int n = S.size();
	
	for (int i = 0, k = 0; i < n; ++i) {
		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);
		}
	}
	
	sort(EP, EP + (2 * n));
	
	set<int> BT;
	int cnt = 0;
	
	for (int i = 0; i < 2 * n; ++i) {
		if (EP[i].type == BOTTOM) {
			BT.insert(EP[i].p.x);
		} else if (EP[i].type == LEFT) {
			auto b = BT.lower_bound(S[EP[i].seg].p1.x);
			auto e = BT.upper_bound(S[EP[i].seg].p2.x);
			cnt += distance(b, e);
		} else if (EP[i].type == TOP) {
			BT.erase(EP[i].p.x);
		}
	}
	
	return cnt;
}

int main() {
	int n; cin >> n;
	vector<Segment> S(n);
	for (int i = 0; i < n; i++) {
		cin >> S[i].p1.x >> S[i].p1.y >> S[i].p2.x >> S[i].p2.y;
	}
	
	cout << manhattanIntersection(S) << endl;
	
	return 0;
}
accuracy: 1
time_ms: 90
memory_kb: 12088
final_rank: 10