<|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.

174. Walls
time limit per test: 0.75 sec.
memory limit per test: 32768 KB
input: standard
output: standard



People of country T-land lived on the big plain many years ago. It is happened so that they started to quarrel, so they began to build walls to separate from each other.
One day they realized that walls surround some part of the country. Your task is to determine which wall was build first to surround a part of the T-land.

Input
The first line of input contains one number M (1<=M<=200000) - number of walls. Each of the following M lines contains four integer numbers: Cartesian coordinates of two ends of each wall. Walls are rectilinear segments with positive length, two walls can cross only by ends, and walls can't coincide. All coordinates do not exceed 10^9 by its absolute values.

Output
Write the answer in the single line of output. If all the walls leave the territory opened, write 0.

Sample test(s)

Input
4
0 0 1 0
0 1 0 0
1 0 0 1
2 2 5 7

Output
3
Author:	Dmitry Orlov
Resource:	Saratov ST team Spring Contest #1
Date:	18.05.2003

<|response|>
1. Abridged problem statement  
We are given M axis-aligned wall segments in the plane. Walls only meet or cross at their endpoints, and no two walls coincide. Walls are added one by one in a given order. We must find the 1-based index of the first wall whose addition closes a cycle of walls (i.e., whose two endpoints were already connected by earlier walls). If no wall ever completes a cycle, output 0.

2. Key observations  
- Model the endpoints as graph vertices and walls as edges in an undirected graph.  
- Adding an edge that connects two vertices already in the same connected component creates a cycle.  
- Disjoint-Set Union (DSU) can maintain connectivity and detect when two vertices are already connected in nearly O(1) amortized time.  
- Each unique endpoint coordinate pair can be mapped to a distinct integer ID using a hash map (or std::map).

3. Full solution approach  
1. Initialize a DSU structure sized for up to 2·M elements, since there are at most 2 endpoints per wall.  
2. Initialize an empty map from point (x,y) to integer ID, and a counter nextID = 0.  
3. For each wall i from 1 to M:  
   a. Read endpoints (x1,y1) and (x2,y2).  
   b. If (x1,y1) is not in the map, assign it map[(x1,y1)] = nextID++. Likewise for (x2,y2).  
   c. Let u = map[(x1,y1)], v = map[(x2,y2)].  
   d. If find(u) == find(v) in the DSU, then adding this edge would form a cycle. Print i and terminate.  
   e. Otherwise, unite(u, v) in the DSU.  
4. If no cycle is found after processing all walls, print 0.

Time complexity: O(M α(M)) for DSU operations plus O(M) expected for map lookups.  
Memory usage: O(M) for DSU and map.

4. C++ implementation with detailed comments  
    #include <bits/stdc++.h>  
    using namespace std;  

    // Disjoint-Set Union (Union-Find) with path compression and union by size  
    class DSU {  
    public:  
        vector<int> parent, sz;  

        DSU(int n) : parent(n), sz(n, 1) {  
            for (int i = 0; i < n; i++)  
                parent[i] = i;  
        }  

        // Find with path compression  
        int find(int x) {  
            if (parent[x] != x)  
                parent[x] = find(parent[x]);  
            return parent[x];  
        }  

        // Unite two sets; returns true if merged, false if already same root  
        bool unite(int a, int b) {  
            a = find(a);  
            b = find(b);  
            if (a == b) return false;  
            // attach smaller tree under larger  
            if (sz[a] > sz[b]) swap(a, b);  
            parent[a] = b;  
            sz[b] += sz[a];  
            return true;  
        }  
    };  

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

        int M;  
        cin >> M;  

        DSU dsu(2 * M);             // At most 2*M distinct endpoints  
        unordered_map<long long,int> mp;  
        mp.reserve(2 * M);          // reserve space to avoid rehashing  
        int nextID = 0;  

        auto getID = [&](int x, int y) {  
            // combine x,y into one 64-bit key  
            long long key = ( (long long)x << 32 ) ^ (unsigned long long)(y & 0xffffffff);  
            auto it = mp.find(key);  
            if (it != mp.end()) return it->second;  
            mp[key] = nextID;  
            return nextID++;  
        };  

        for (int i = 1; i <= M; i++) {  
            int x1, y1, x2, y2;  
            cin >> x1 >> y1 >> x2 >> y2;  

            int u = getID(x1, y1);  
            int v = getID(x2, y2);  

            // If u and v are already connected, this edge forms a cycle  
            if (!dsu.unite(u, v)) {  
                cout << i << "\n";  
                return 0;  
            }  
        }  

        // No cycle was ever formed  
        cout << 0 << "\n";  
        return 0;  
    }  

5. Python implementation with detailed comments  
    import sys  
    sys.setrecursionlimit(10**7)  

    class DSU:  
        def __init__(self, n):  
            self.parent = list(range(n))  
            self.size = [1] * n  

        def find(self, x):  
            if self.parent[x] != x:  
                self.parent[x] = self.find(self.parent[x])  
            return self.parent[x]  

        def unite(self, a, b):  
            ra = self.find(a)  
            rb = self.find(b)  
            if ra == rb:  
                return False    # already in same set → would form a cycle  
            if self.size[ra] > self.size[rb]:  
                ra, rb = rb, ra  
            self.parent[ra] = rb  
            self.size[rb] += self.size[ra]  
            return True  

    def main():  
        data = sys.stdin.read().split()  
        it = iter(data)  
        M = int(next(it))  

        dsu = DSU(2 * M)     # at most 2*M unique endpoints  
        point_id = {}        # map (x,y) → unique integer ID  
        next_id = 0  

        for i in range(1, M + 1):  
            x1 = int(next(it)); y1 = int(next(it))  
            x2 = int(next(it)); y2 = int(next(it))  

            # assign/get ID for first endpoint  
            if (x1, y1) not in point_id:  
                point_id[(x1, y1)] = next_id  
                next_id += 1  
            u = point_id[(x1, y1)]  

            # assign/get ID for second endpoint  
            if (x2, y2) not in point_id:  
                point_id[(x2, y2)] = next_id  
                next_id += 1  
            v = point_id[(x2, y2)]  

            # if unite returns False, a cycle is formed here  
            if not dsu.unite(u, v):  
                print(i)  
                return  

        # no cycle formed after all walls  
        print(0)  

    if __name__ == "__main__":  
        main()