// Arup Guha
// 11/15/2018
// Solution to 2018 SER D1/D2 Problem: Rectangles

import java.util.*;
import java.io.*;

public class rectangles {
	
	public static int n;
	public static int[][] rawdata;
	
	public static HashMap<Integer,Integer> xmap;
	public static HashMap<Integer,Integer> ymap;
	
	public static void main(String[] args) throws Exception {
		
		BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
		n = Integer.parseInt(stdin.readLine().trim());
		rawdata = new int[n][4];
		TreeSet<Integer> xvals = new TreeSet<Integer>();
		TreeSet<Integer> yvals = new TreeSet<Integer>();
		
		// Just read in the raw data, keeping note of unique x's and y's.
		for (int i=0; i<n; i++) {
			StringTokenizer tok = new StringTokenizer(stdin.readLine());
			for (int j=0; j<4; j++) {
				rawdata[i][j] = Integer.parseInt(tok.nextToken());
				if (j%2 == 0) xvals.add(rawdata[i][j]);
				else          yvals.add(rawdata[i][j]);
			}
		}
		
		// Extract unique x's in sorted order. And store compressed map.
		int[] allx = new int[xvals.size()];
		int idx = 0;
		while (xvals.size() > 0) allx[idx++] = xvals.pollFirst();
		xmap = new HashMap<Integer,Integer>();
		for (int i=0; i<allx.length; i++) xmap.put(allx[i], i);
		
		// Do same for y.
		int[] ally = new int[yvals.size()];
		idx = 0;
		while (yvals.size() > 0) ally[idx++] = yvals.pollFirst();
		ymap = new HashMap<Integer,Integer>();
		for (int i=0; i<ally.length; i++) ymap.put(ally[i], i);
		
		// Store all events here. events[i] stores each event that occurs at the ith smallest y value.
		ArrayList[] events = new ArrayList[ally.length];
		for (int i=0; i<events.length; i++) events[i] = new ArrayList<event>();
		
		// Go through raw data and create two events for each rectangle.
		for (int i=0; i<n; i++) {
			int x1 = xmap.get(rawdata[i][0]);
			int x2 = xmap.get(rawdata[i][2]);
			int y1 = ymap.get(rawdata[i][1]);
			int y2 = ymap.get(rawdata[i][3]);
			events[y1].add(new event(x1,x2));
			events[y2].add(new event(x1,x2));
		}
		
		// My segment tree that keeps track of ranges in x.
		IntTree mysegtree = new IntTree(1, allx.length-1, allx);
		long res = 0;
		
		// Our vertical sweep, from small to large y values.
		for (int i=0; i<events.length; i++) {
			
			// Process each event
			for (event e: (ArrayList<event>)events[i]) mysegtree.change(e.leftx+1, e.rightx);
			
			// Add in the sum of areas of the rectangles that were "on" in the last horizontal strip.
			if (i<events.length-1) res += ((long)mysegtree.query(1, allx.length-1))*(ally[i+1]-ally[i]);
		}
		
		// Ta da!
		System.out.println(res);
	}
}

class event {
	
	public int leftx;
	public int rightx;
	
	public event(int x1, int x2) {
		leftx = x1;
		rightx = x2;
	}
}

/*** Segment Tree for a weighted XOR ***/

class IntTree {

	// Stores range for this node.
	public int low;
	public int high;

	// Stores aggregate data for this node.
	public boolean delta;
	public int total;
	public int cur;

	// Pointers to children.
	public IntTree left;
	public IntTree right;

	// Creates an interval tree from myLow to myHigh, inclusive.
	public IntTree(int myLow, int myHigh, int[] cumfreq) {

		low = myLow;
		high = myHigh;
		delta = false;
		total = cumfreq[myHigh] - cumfreq[myLow-1];
		cur = 0;

		// Lowest level.
		if (low == high) {
			left = null;
			right = null;
		}

		// Must create more nodes.
		else {
			int mid = (low+high)/2;
			left = new IntTree(low, mid, cumfreq);
			right = new IntTree(mid+1, high, cumfreq);
		}
	}

	// Propagates a change down to child nodes.
	public void prop() {

		// Recursive case, push down.
		if (left != null) {
			if (delta) {
				left.delta = !left.delta;
				right.delta = !right.delta;
				delta = false;
			}
		}
	}

	// Pre-condition: delta is false.
	public void update() {
		if (left != null) {
			int leftcur = left.delta ? left.total-left.cur : left.cur;
			int rightcur = right.delta ? right.total-right.cur : right.cur;
			cur = leftcur + rightcur;
		}
	}

	// Flips the range [start, end].
	public void change(int start, int end) {

		// Out of range.
		if (high < start || end < low) return;

		// Push down delta.
		prop();

		if (start <= low && high <= end) {
			delta = !delta;
			update();
			return;
		}

		// Portions of children have to be changed instead.
		left.change(start, end);
		right.change(start, end);
		update();
	}

	public int query(int start, int end) {

		// Out of range.
		if (high < start || end < low) {
			return  0;
		}

		// Whole range must be returned;
		if (start <= low && high <= end) {
			return delta ? total-cur : cur;
		}

		// Get answers from both potions.
		prop();
		int leftSide = left.query(start, end);
		int rightSide = right.query(start, end);
		update();
		return leftSide+rightSide;
	}
}
