#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;
}