```go
package main
import (
"bufio"
"fmt"
"os"
"sort"
)
// event represents a vertical line sweep event.
// type_: 1 for adding a segment, -1 for removing.
type event struct {
x, type_, y1, y2 int
}
// node represents a segment tree node.
// cnt: number of active rectangles covering this range completely.
// len: length of the covered Y-interval within this node's range.
type node struct {
cnt, len int
}
var (
tree []node
ys []int
)
func main() {
reader := bufio.NewReader(os.Stdin)
writer := bufio.NewWriter(os.Stdout)
defer writer.Flush()
var n int
fmt.Fscan(reader, &n)
events := make([]event, 0, 2*n)
ys = make([]int, 0, 2*n)
for i := 0; i < n; i++ {
var x1, y1, x2, y2 int
fmt.Fscan(reader, &x1, &y1, &x2, &y2)
// Normalize coordinates so x1 <= x2 and y1 <= y2
if x1 > x2 {
x1, x2 = x2, x1
}
if y1 > y2 {
y1, y2 = y2, y1
}
// The problem defines segments of width 1 square.
// A segment from x1 to x2 covers cells [x1, x2].
// In continuous coordinates, this corresponds to the interval [x1, x2 + 1).
// Same for y.
x2++
y2++
events = append(events, event{x: x1, type_: 1, y1: y1, y2: y2})
events = append(events, event{x: x2, type_: -1, y1: y1, y2: y2})
ys = append(ys, y1, y2)
}
// Coordinate compression for Y values
sort.Ints(ys)
uniqueYs := 0
if len(ys) > 0 {
uniqueYs = 1
for i := 1; i < len(ys); i++ {
if ys[i] != ys[i-1] {
ys[uniqueYs] = ys[i]
uniqueYs++
}
}
ys = ys[:uniqueYs]
}
// Sort events by x coordinate
sort.Slice(events, func(i, j int) bool {
return events[i].x < events[j].x
})
if len(ys) < 2 {
fmt.Fprintln(writer, 0)
return
}
// Initialize segment tree
// The tree manages intervals between sorted unique Y coordinates.
// There are len(ys)-1 elementary intervals.
tree = make([]node, 4*len(ys))
var ans int64
prevX := events[0].x
for _, e := range events {
width := e.x - prevX
// Add area covered in the strip [prevX, e.x)
if width > 0 {
ans += int64(width) * int64(tree[1].len)
}
// Update the active intervals in the segment tree
idx1 := sort.SearchInts(ys, e.y1)
idx2 := sort.SearchInts(ys, e.y2)
// We want to update the range of elementary intervals [idx1, idx2-1]
if idx1 < idx2 {
update(1, 0, len(ys)-2, idx1, idx2-1, e.type_)
}
prevX = e.x
}
fmt.Fprintln(writer, ans)
}
// update modifies the coverage count in the segment tree
// v: current node index
// tl, tr: current node's range of leaf indices (elementary intervals)
// l, r: target range of leaf indices to update
// add: +1 or -1
func update(v, tl, tr, l, r, add int) {
if l > r {
return
}
if l == tl && r == tr {
tree[v].cnt += add
} else {
tm := (tl + tr) / 2
update(2*v, tl, tm, l, min(r, tm), add)
update(2*v+1, tm+1, tr, max(l, tm+1), r, add)
}
pushUp(v, tl, tr)
}
// pushUp recalculates the covered length of the node based on its children and count
func pushUp(v, tl, tr int) {
if tree[v].cnt > 0 {
// If this node is fully covered, its length is the full Y range it spans
tree[v].len = ys[tr+1] - ys[tl]
} else {
// If not fully covered, length is sum of children's lengths (if not leaf)
if tl != tr {
tree[v].len = tree[2*v].len + tree[2*v+1].len
} else {
tree[v].len = 0
}
}
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
```