#include<bits/stdc++.h>
// #include<ext/pb_ds/assoc_container.hpp>
// #include<ext/pb_ds/tree_policy.hpp>
using namespace std;
// using namespace __gnu_pbds;

#define ll               long long
#define int              long long
#define ull              unsigned long long
#define ff               first
#define ss               second
#define pb               push_back
#define mp               make_pair
#define pii              pair<int,int>
#define vi               vector<int>
#define vll              vector<ll> 
#define vvi              vector< vector<int>>
#define vvll             vector< vector<ll>>
#define vpii             vector<pair<int,int>>
#define mii              map<int,int>
#define pqb              priority_queue<int>
#define pqs              priority_queue<int, vector<int>, greater<int>>
#define setbits(x)       __builtin_popcountll(x)
#define zrobits(x)       __builtin_ctzll(x)
#define mod              1000000007
#define inf              1e18
#define ps(x,y)          fixed<<setprecision(y)<<x
#define mk(arr, n, type) type *arr=new type[n];
#define wt(x)            int x; cin>>x; while( x-- )
#define rep(i,a,b)       for( int i=a; i<=b; i++ )
#define repi(i,a,b)      for( int i=a; i>=b; i-- )
#define sp               ' '
#define nl               char(10)
#define endl             char(10)
#define PRT(ar)          for( auto i : ar ) cout<<i<<sp; cout<<nl;
#define mems(x,ch)       memset(x,ch,sizeof(x))
#define sortv(x)         sort(x.begin(),x.end())
#define sortvr(x)        sort(x.rbegin(),x.rend())
#define all(x)           x.begin(), x.end()

const ll N = 1e5 + 5;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
// typedef tree< int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> pbds;

void fastIO() {
	ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	// #ifndef ONLINE_JUDGE
	//     freopen("input.txt", "r", stdin);
	//     freopen("output.txt", "w", stdout);
	// #endif
}





class Solution {
	void dfs(int node, vvi& adj, vi& vis, int& no_of_odd_deg) {
		vis[node] = 1;
		if ((adj[node].size() % 2)) no_of_odd_deg++;
		for (auto nbr : adj[node]) {
			if (!vis[nbr])
				dfs(nbr, adj, vis, no_of_odd_deg);
		}
	}
public:
	int solve(int n, vvi& adj) {
		vi vis(n, 0);
		int con_cc = 0; // no of connected component
		int odd_vertex = 0;

		for (int i = 0; i < n; i++) {
			if (!vis[i]) {
				int no_of_odd_deg = 0;
				con_cc++;
				dfs(i, adj, vis, no_of_odd_deg);
				if (no_of_odd_deg <= 2) odd_vertex += 2;
				else odd_vertex += no_of_odd_deg;
			}
		}

		int ans = max(con_cc - 1, (odd_vertex - 1) / 2);
		return ans;
	}
};



int32_t main() {
	fastIO();
	Solution sol;

	int m; cin >> m;
	int k = 0;
	map<pii, int> mpp;
	vvi tmp;

	for (int i = 0; i < m; i++) {
		int x1, y1, x2, y2; cin >> x1 >> y1 >> x2 >> y2;
		if (mpp.count({ x1, y1 }) == 0) {
			mpp[{x1, y1}] = k++;
		}
		if (mpp.count({ x2,y2 }) == 0) {
			mpp[{x2, y2}] = k++;
		}
		tmp.push_back({ x1,y1,x2,y2 });
	}

	// cout<<k;
	int n = k;
	vvi adj(n);
	for (auto x : tmp) {
		int u = mpp[{x[0], x[1]}];
		int v = mpp[{x[2], x[3]}];
		adj[u].pb(v);
		adj[v].pb(u);
	}

	auto ans = sol.solve(n, adj);
	cout << ans;
	return 0;
}