```go
package main
import (
"bufio"
"fmt"
"math/big"
"os"
"sort"
)
type Vec struct {
x, y int64
}
func quad(x, y int64) int {
if x > 0 && y >= 0 {
return 1
}
if x <= 0 && y > 0 {
return 2
}
if x < 0 && y <= 0 {
return 3
}
if x >= 0 && y < 0 {
return 4
}
return 0
}
type Group struct {
sumX, sumY int64
dirX, dirY int64
}
func main() {
scanner := bufio.NewScanner(os.Stdin)
scanner.Split(bufio.ScanWords)
scanner.Buffer(make([]byte, 1024*1024), 1024*1024)
nextInt := func() int64 {
scanner.Scan()
res := int64(0)
for _, b := range scanner.Bytes() {
res = res*10 + int64(b-'0')
}
return res
}
if !scanner.Scan() {
return
}
n := 0
for _, b := range scanner.Bytes() {
n = n*10 + int(b-'0')
}
vecs := make([]Vec, 0, n)
for i := 0; i < n; i++ {
a := nextInt()
b := nextInt()
c := nextInt()
d := nextInt()
x := a - b
y := c - d
if x == 0 && y == 0 {
continue
}
vecs = append(vecs, Vec{x, y})
}
if len(vecs) == 0 {
fmt.Println(0)
return
}
sort.Slice(vecs, func(i, j int) bool {
q1 := quad(vecs[i].x, vecs[i].y)
q2 := quad(vecs[j].x, vecs[j].y)
if q1 != q2 {
return q1 < q2
}
return vecs[i].x*vecs[j].y-vecs[j].x*vecs[i].y > 0
})
var merged []Group
for _, v := range vecs {
if len(merged) > 0 {
last := &merged[len(merged)-1]
if quad(last.dirX, last.dirY) == quad(v.x, v.y) && last.dirX*v.y-v.x*last.dirY == 0 {
last.sumX += v.x
last.sumY += v.y
continue
}
}
merged = append(merged, Group{sumX: v.x, sumY: v.y, dirX: v.x, dirY: v.y})
}
M := len(merged)
for i := 0; i < M; i++ {
merged = append(merged, merged[i])
}
prefX := make([]int64, 2*M+1)
prefY := make([]int64, 2*M+1)
for i := 0; i < 2*M; i++ {
prefX[i+1] = prefX[i] + merged[i].sumX
prefY[i+1] = prefY[i] + merged[i].sumY
}
var maxSq big.Int
var tempX, tempY, sqX, sqY, sq big.Int
updateMax := func(x, y int64) {
tempX.SetInt64(x)
tempY.SetInt64(y)
sqX.Mul(&tempX, &tempX)
sqY.Mul(&tempY, &tempY)
sq.Add(&sqX, &sqY)
if sq.Cmp(&maxSq) > 0 {
maxSq.Set(&sq)
}
}
getSum := func(L, R int) (int64, int64) {
if L > R {
return 0, 0
}
return prefX[R+1] - prefX[L], prefY[R+1] - prefY[L]
}
j := 0
for i := 0; i < M; i++ {
if j <= i {
j = i + 1
}
for j < i+M {
cross := merged[i].dirX*merged[j].dirY - merged[j].dirX*merged[i].dirY
if cross > 0 {
j++
} else {
break
}
}
hasOpp := false
if j < i+M {
cross := merged[i].dirX*merged[j].dirY - merged[j].dirX*merged[i].dirY
if cross == 0 {
dot := merged[i].dirX*merged[j].dirX + merged[i].dirY*merged[j].dirY
if dot < 0 {
hasOpp = true
}
}
}
x, y := getSum(i+1, j-1)
updateMax(x, y)
x, y = getSum(i, j-1)
updateMax(x, y)
if hasOpp {
x, y = getSum(i+1, j)
updateMax(x, y)
x, y = getSum(i, j)
updateMax(x, y)
}
}
fmt.Println(maxSq.String())
}
```