<|instruction|>
Solve the below problem. The solution should start with an abridged problem statement. Then key observations. Then full solution based on the observations. Then C++ and Python implementations with comments.

496. L-Shapes
Time limit per test: 0.75 second(s)
Memory limit: 262144 kilobytes
input: standard
output: standard



Let's say that two line segments of non-zero length form an  if they are at a  angle to each other and one endpoint of one segment coincides with one endpoint of the other.

There are N line segments on a plane. The segments are numbered from 1 to N. Count the number of distinct pairs of segments that form L-shapes. Two pairs are considered distinct if they contain segments with different numbers.

Input
The first line of the input line contains the integer N (1 ≤ N ≤ 5000). Each of the following N lines describes one segment and contains four integers x1, y1, x2, y2 (), where (x1, y1) and (x2, y2) are endpoints of the segment. It may be assumed that for each segment x1 ≠q x2 or y1 ≠q y2.

Output
The output file should contain a single integer, the total number of distinct pairs of line segments forming L-shapes.

Example(s)
sample input
sample output
7
0 4 0 7
4 4 1 6
1 6 -3 0
4 4 0 4
0 0 0 4
0 0 0 2
0 4 4 4
5



Note. In the example the L-shapes are formed by the following pairs of segments: (1, 4), (1, 7), (2, 3), (4, 5), (5, 7). Note that the segments 4 and 7 coincide, but the pairs (1, 4) and (1, 7), for example, are still considered distinct.

<|response|>
1. Abridged Problem Statement  
Given N (1 ≤ N ≤ 5000) non‐degenerate line segments on the plane, count the number of unordered pairs of segments that form an “L‐shape.” Two segments form an L‐shape if  
  • They share exactly one endpoint.  
  • They meet at a right angle at that shared endpoint.  

2. Key Observations  
- Any L‐shape must occur at a shared endpoint P.  
- At P, each segment contributes a direction vector (dx,dy). Two segments are perpendicular exactly when their direction vectors have dot product zero.  
- Checking all O(N²) pairs is too slow for N=5000.  
- Instead, group segments by each endpoint P, and at P count how many segments go in each direction.  
- For each direction d at P, the perpendicular direction is p = (–d.y, d.x). If at P there are c(d) segments in direction d and c(p) in direction p, they form c(d)·c(p) L‐shapes.  
- Summing c(d)·c(p) over all directions d at P double‐counts each unordered pair (once as (d,p) and once as (p,d)), so we divide by 2.  
- Finally, sum over all points P to get the answer.

3. Full Solution Approach  
Step 1: Normalize Directions  
  - For a segment from (x₁,y₁) to (x₂,y₂), compute raw vector (dx,dy)=(x₂−x₁,y₂−y₁).  
  - Divide by g = gcd(|dx|,|dy|) to make it primitive.  
  - Enforce a canonical orientation so that each collinear set of vectors maps to the same key:  
    • If dx<0, flip both dx,dy → (−dx,−dy).  
    • Else if dx==0, force dy=+1.  
    • Else if dy==0, force dx=+1.  
  - Result: a unique (dx,dy) for each line‐of‐sight direction.

Step 2: Build Endpoint‐to‐Direction Counts  
  - Use a map from point P=(x,y) to another map that counts how many segments at P have each normalized direction d.  
  - For each segment, after computing its normalized d, increment count at both endpoints P₁ and P₂.

Step 3: Count L‐Shapes at Each Point  
  - For each point P, let M be the map direction→count.  
  - Initialize local_sum = 0.  
  - For each (d = (dx,dy), c = M[d]):  
      • Compute its perpendicular p = (–dy, dx).  
      • Re‐normalize p with the same rules to match keys in M.  
      • If M contains p with count c′, add c·c′ to local_sum.  
  - The unordered pairs at P are local_sum/2 (because (d,p) and (p,d) both contributed).

Step 4: Aggregate  
  - Sum local_sum/2 over all points P.  
  - Print the total.

Complexity:  
  - Normalizing each segment: O(log max‐coord) for gcd.  
  - Inserting into maps: O(log N) each.  
  - Total ≈ O(N·log N). Fits within the limits.

4. C++ Implementation with Detailed Comments  
```cpp
#include <bits/stdc++.h>
using namespace std;

// Helper to compute gcd
static int mygcd(int a, int b) {
    return b == 0 ? abs(a) : mygcd(b, a % b);
}

// Normalize a direction vector (dx,dy) to a canonical primitive form
pair<int,int> normalize(int dx, int dy) {
    int g = mygcd(dx, dy);
    dx /= g; 
    dy /= g;
    // Enforce unique sign convention
    if (dx < 0) {
        dx = -dx;
        dy = -dy;
    }
    if (dx == 0) {
        // Pure vertical: force dy = +1
        dy = 1;
    }
    if (dy == 0) {
        // Pure horizontal: force dx = +1
        dx = 1;
    }
    return {dx, dy};
}

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

    int N;
    cin >> N;
    // Map: point (x,y) -> map of direction (dx,dy) -> count
    map<pair<int,int>, map<pair<int,int>,int>> mp;

    for (int i = 0; i < N; i++) {
        int x1, y1, x2, y2;
        cin >> x1 >> y1 >> x2 >> y2;
        // Compute and normalize direction
        int raw_dx = x2 - x1;
        int raw_dy = y2 - y1;
        auto d = normalize(raw_dx, raw_dy);
        // Increment count at both endpoints
        mp[{x1, y1}][d]++;
        mp[{x2, y2}][d]++;
    }

    long long answer = 0;
    // Process each shared point
    for (auto &entry : mp) {
        auto &dirCount = entry.second;
        long long localSum = 0;
        // For each direction at this point
        for (auto &kv : dirCount) {
            auto d = kv.first;
            long long c = kv.second;
            // Compute perpendicular: p = (-dy, dx)
            int pdx = -d.second;
            int pdy =  d.first;
            // Re‐normalize so it matches our stored keys
            auto p = normalize(pdx, pdy);
            // If that perpendicular also appears here, add c * c'
            auto it = dirCount.find(p);
            if (it != dirCount.end()) {
                localSum += c * it->second;
            }
        }
        // Each unordered pair counted twice
        answer += localSum / 2;
    }

    cout << answer << "\n";
    return 0;
}
```

5. Python Implementation with Detailed Comments  
```python
import sys
import math

def normalize(dx, dy):
    """Return a canonical primitive direction for vector (dx,dy)."""
    g = math.gcd(dx, dy)
    dx //= g
    dy //= g
    # Enforce unique sign convention
    if dx < 0:
        dx, dy = -dx, -dy
    if dx == 0:
        # Pure vertical: force dy = +1
        dy = 1
    if dy == 0:
        # Pure horizontal: force dx = +1
        dx = 1
    return dx, dy

def main():
    input = sys.stdin.readline
    N = int(input())
    # Map: point -> { direction: count }
    mp = {}

    # Read segments, update counts
    for _ in range(N):
        x1, y1, x2, y2 = map(int, input().split())
        dx, dy = x2 - x1, y2 - y1
        d = normalize(dx, dy)
        for pt in ((x1, y1), (x2, y2)):
            if pt not in mp:
                mp[pt] = {}
            mp[pt][d] = mp[pt].get(d, 0) + 1

    total = 0
    # For each shared endpoint, count perpendicular pairs
    for dirCount in mp.values():
        local_sum = 0
        for (dx, dy), c in dirCount.items():
            # perpendicular direction
            pdx, pdy = -dy, dx
            p = normalize(pdx, pdy)
            c2 = dirCount.get(p, 0)
            local_sum += c * c2
        # Each unordered pair counted twice
        total += local_sum // 2

    print(total)

if __name__ == "__main__":
    main()
```