#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cassert>

#define M 1600010
#define Inf 1000000007
#define Start_node 0
#define End_node 3
#define Start_line 1
#define End_line 2
#define lc (now * 2)
#define rc (now * 2 + 1)
#define mid (L + R >> 1)

using namespace std;

struct Line
{
    int x, y, len, id;
};

struct node
{
    int x, y, id, op;
};

Line Hang[M], Lie[M];

int CntHang = 0, CntLie = 0, Cnt = 0;

node Tmp[M];

int F[M], Tag[M], Size[M];

long long Ans[M], ans = 0;

int getfa(int x)
{
    return (F[x] == x) ? x : (F[x] = getfa(F[x]));
}

inline bool cmp2(node x, node y)
{
    return x.x < y.x || x.x == y.x && x.op < y.op || x.x == y.x && x.op == y.op && x.y < y.y;
}

inline bool cmp3(node x, node y)
{
    return x.y < y.y || x.y == y.y && x.op < y.op || x.y == y.y && x.op == y.op && x.id < y.id;
}

inline void Merge(int x, int y)
{
    if(x && y && getfa(x) != getfa(y)) F[getfa(x)] = getfa(y);
}

inline void Down(int now, int L, int R)
{
    if(Tag[now])
    {
        if(Size[lc]) Merge(Tag[lc], Tag[now]);
        if(Size[rc]) Merge(Tag[rc], Tag[now]);
        Tag[lc] = Tag[rc] = Tag[now];
        Tag[now] = 0;
    }
}

int tmp = 0;

void Insert(int now, int L, int R, int who)
{
    if(L == R)
    {
        //if(Size[now]) Merge(Tag[now], who);
        Tag[now] = Tmp[who].id;
        Size[now] = 1;
        return;
    }
    Size[now]++;
    Down(now, L, R);
    if(Tmp[who].y <= mid) Insert(lc, L, mid, who);
    else Insert(rc, mid + 1, R, who);
}

void Delete(int now, int L, int R, int who)
{
    if(L == R)
    {
        if(Size[now]) Merge(Tag[now], Tmp[who].id);
        Size[now] = 0;
        Tag[now] = 0;
        return;
    }
    Size[now]--;
    Down(now, L, R);
    if(Tmp[who].y <= mid) Delete(lc, L, mid, who);
    else Delete(rc, mid + 1, R, who);
}

void Query(int now, int L, int R, int l, int r, int who)
{
    if(L == l && R == r)
    {
        if(Size[now]) Merge(Tag[now], who);
        if(!Tag[now]) Tag[now] = who;
        Ans[who] -= Size[now];
        return;
    }
    Down(now, L, R);
    if(l <= mid) Query(lc, L, mid, l, min(mid, r), who);
    if(r > mid) Query(rc, mid + 1, R, max(l, mid + 1), r, who);
}

void Dfly(int now, int L, int R)
{
    if(L == R) return;
    Down(now, L, R);
    Dfly(lc, L, mid);
    Dfly(rc, mid + 1, R);
}

int main()
{
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
    {
        F[i] = i;
        int a1, b1, a2, b2;
        scanf("%d%d%d%d", &a1, &b1, &a2, &b2);
        if(a1 > a2 || b1 > b2) a1 ^= a2 ^= a1 ^= a2, b1 ^= b2 ^= b1 ^= b2;
        if(b1 == b2)
            Hang[++CntHang] = (Line){a1, b1, a2 - a1 + 1, i},
            Tmp[++Cnt] = (node){a1, b1, CntHang, Start_node},
            Tmp[++Cnt] = (node){a2, b2, CntHang, End_node};
        else
            Lie[++CntLie] = (Line){a1, b1, b2 - b1 + 1, i},
            Tmp[++Cnt] = (node){a1, b1, CntLie, Start_line},
            Tmp[++Cnt] = (node){a2, b2, CntLie, End_line};
    }
    sort(Tmp + 1, Tmp + Cnt + 1, cmp3);
    int t = 1;
    for(int i = 1; i <= Cnt; i++)
        Tmp[i].y = (Tmp[i].y == Tmp[i + 1].y) ? t : t++;
    t *= 2;
    sort(Tmp + 1, Tmp + Cnt + 1, cmp2);
    for(int i = 1; i <= Cnt; i++)
    {
        if(Tmp[i].op == Start_node)
            Insert(1, 1, t, i);
        if(Tmp[i].op == End_node)
            Delete(1, 1, t, i);
        if(Tmp[i].op == Start_line)
        {
            Query(1, 1, t, Tmp[i].y, Tmp[i + 1].y, Tmp[i].id + CntHang);
            i++;
        }
    }
    //Dfly(1, 1, t);
    for(int i = 1; i <= n; i++)
        if(i != getfa(i)) Ans[getfa(i)] += Ans[i];
    for(int i = 1; i <= CntHang; i++)
        Ans[getfa(i)] += Hang[i].len;
    for(int i = CntHang + 1; i <= n; i++)
        Ans[getfa(i)] += Lie[i - CntHang].len;
    for(int i = 1; i <= n; i++)
        ans = max(ans, Ans[i]);
    printf("%lld\n", ans - 1);
    return 0;
}
/*
2
0 0 0 1
1 0 1 1
1

4
0 0 1 0
0 0 0 1
1 -1 1 2
0 1 1 1
5

20
0 0 9 0
0 1 9 1
0 2 9 2
0 3 9 3
0 4 9 4
0 5 9 5
0 6 9 6
0 7 9 7
0 8 9 8
0 9 9 9
0 0 0 9
1 0 1 9
2 0 2 9
3 0 3 9
4 0 4 9
5 0 5 9
6 0 6 9
7 0 7 9
8 0 8 9
9 0 9 9
99

5
-5 1 -5 5
0 2 4 2
1 3 3 3
2 0 2 4
5 1 5 5
10

5
1 -5 5 -5
2 0 2 4
3 1 3 3
0 2 4 2
1 5 5 5
10

4
0 0 1 0
0 0 0 3
0 3 1 3
1 1 1 2
5

3
-1 0 -1 1
4 -2 4 3
5 -3 5 2
5

4
-1000000000 -1000000000 1000000000 -1000000000
-1000000000 -1000000000 -1000000000 1000000000
1000000000 -1000000000 1000000000 1000000000
-1000000000 1000000000 1000000000 1000000000
7999999999

1
0 0 0 1
1

*/


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cassert>

#define M 1600010
#define Inf 1000000007
#define Start_node 0
#define End_node 2
#define line 1
#define lc (now * 2)
#define rc (now * 2 + 1)
#define mid (L + R >> 1)

using namespace std;

struct Line
{
    int x, y, len, id;
};

struct node
{
    int x, y, id, op;
};

Line Hang[M], Lie[M];

int CntHang = 0, CntLie = 0, Cnt = 0;

node Tmp[M];

int F[M], Tag[M], Size[M];

long long Ans[M], ans = 0;

int getfa(int x)
{
    return (F[x] == x) ? x : (F[x] = getfa(F[x]));
}

inline bool cmp2(node x, node y)
{
    return x.x < y.x || x.x == y.x && x.op < y.op || x.x == y.x && x.op == y.op && x.y < y.y;
}

inline bool cmp3(node x, node y)
{
    return x.y < y.y || x.y == y.y && x.op < y.op || x.y == y.y && x.op == y.op && x.id < y.id;
}

inline void Merge(int x, int y)
{
    if(x && y && getfa(x) != getfa(y)) F[getfa(x)] = getfa(y);
}

inline void Down(int now, int L, int R)
{
    if(Tag[now])
    {
        if(Size[lc]) Merge(Tag[lc], Tag[now]);
        if(Size[rc]) Merge(Tag[rc], Tag[now]);
        Tag[lc] = Tag[rc] = Tag[now];
        Tag[now] = 0;
    }
}

int tmp = 0;

void Insert(int now, int L, int R, int who)
{
    if(L == R)
    {
        Tag[now] = Tmp[who].id;
        Size[now] = 1;
        return;
    }
    Size[now]++;
    Down(now, L, R);
    if(Tmp[who].y <= mid) Insert(lc, L, mid, who);
    else Insert(rc, mid + 1, R, who);
}

void Delete(int now, int L, int R, int who)
{
    if(L == R)
    {
		if(Size[now]) Merge(Tag[now], Tmp[who].id);
        Size[now] = 0;
        Tag[now] = 0;
        return;
    }
    Size[now]--;
    Down(now, L, R);
    if(Tmp[who].y <= mid) Delete(lc, L, mid, who);
    else Delete(rc, mid + 1, R, who);
}

void Query(int now, int L, int R, int l, int r, int who)
{
    if(L == l && R == r)
    {
        if(Size[now]) Merge(Tag[now], who);
		if(!Tag[now]) Tag[now] = who;
        Ans[who] -= Size[now];
        return;
    }
    Down(now, L, R);
    if(l <= mid) Query(lc, L, mid, l, min(mid, r), who);
    if(r > mid) Query(rc, mid + 1, R, max(l, mid + 1), r, who);
}

int main()
{
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
    {
        F[i] = i;
        int a1, b1, a2, b2;
        scanf("%d%d%d%d", &a1, &b1, &a2, &b2);
        if(a1 > a2 || b1 > b2) a1 ^= a2 ^= a1 ^= a2, b1 ^= b2 ^= b1 ^= b2;
        if(b1 == b2)
            Hang[++CntHang] = (Line){a1, b1, a2 - a1 + 1, i},
            Tmp[++Cnt] = (node){a1, b1, CntHang, Start_node},
            Tmp[++Cnt] = (node){a2, b2, CntHang, End_node};
        else
            Lie[++CntLie] = (Line){a1, b1, b2 - b1 + 1, i},
            Tmp[++Cnt] = (node){a1, b1, CntLie, line},
            Tmp[++Cnt] = (node){a2, b2, CntLie, line};
    }
    for(int i = 1; i <= Cnt; i++)
    	if(Tmp[i].op == 1) Tmp[i].id += CntHang;
    sort(Tmp + 1, Tmp + Cnt + 1, cmp3);
    int t = 1;
    for(int i = 1; i <= Cnt; i++)
        Tmp[i].y = (Tmp[i].y == Tmp[i + 1].y) ? t : t++;
    sort(Tmp + 1, Tmp + Cnt + 1, cmp2);
    for(int i = 1; i <= Cnt; i++)
    {
        if(Tmp[i].op == Start_node)
            Insert(1, 1, t, i);
        if(Tmp[i].op == End_node)
            Delete(1, 1, t, i);
        if(Tmp[i].op == line)
        {
            Query(1, 1, t, Tmp[i].y, Tmp[i + 1].y, Tmp[i].id);
            i++;
        }
    }
    for(int i = 1; i <= n; i++)
        if(i != getfa(i)) Ans[getfa(i)] += Ans[i];
    for(int i = 1; i <= CntHang; i++)
        Ans[getfa(i)] += Hang[i].len;
    for(int i = CntHang + 1; i <= n; i++)
        Ans[getfa(i)] += Lie[i - CntHang].len;
    for(int i = 1; i <= n; i++)
        ans = max(ans, Ans[i]);
    printf("%lld\n", ans - 1);
    return 0;
}


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cassert>

#define M 1600010
#define Inf 1000000007
#define Start_node 0
#define End_node 3
#define Start_line 1
#define End_line 2
#define lc (now * 2)
#define rc (now * 2 + 1)
#define mid (L + R >> 1)

using namespace std;

struct Line
{
    int x, y, len, id;
};

struct node
{
    int x, y, id, op;
};

Line Hang[M], Lie[M];

int CntHang = 0, CntLie = 0, Cnt = 0;

node Tmp[M];

int F[M], Tag[M], Size[M];

long long Ans[M], ans = 0;

int getfa(int x)
{
    return (F[x] == x) ? x : (F[x] = getfa(F[x]));
}

inline bool cmp(Line x, Line y)
{
    return x.x < y.x || x.x == y.x && x.id < y.id;
}

inline bool cmp2(node x, node y)
{
    return x.x < y.x || x.x == y.x && x.op < y.op || x.x == y.x && x.op == y.op && x.y < y.y;
}

inline bool cmp3(node x, node y)
{
    return x.y < y.y || x.y == y.y && x.op < y.op || x.y == y.y && x.op == y.op && x.id < y.id;
}

inline void Merge(int x, int y)
{
    if(x && y && getfa(x) != getfa(y)) F[x] = y;
}

inline void Down(int now, int L, int R)
{
    if(Tag[now])
    {
        if(Size[lc]) Merge(Tag[lc], Tag[now]);
        if(Size[rc]) Merge(Tag[rc], Tag[now]);
        Tag[lc] = Tag[rc] = Tag[now];
        Tag[now] = 0;
    }
}

int tmp = 0;

void Insert(int now, int L, int R, int who)
{
    if(L == R)
    {
        if(Size[now])
        {
            tmp++;
        }
        if(Size[now]) Merge(Tag[now], who);
        Tag[now] = Tmp[who].id;
        Size[now] = 1;
        return;
    }
    Size[now]++;
    Down(now, L, R);
    if(Tmp[who].y <= mid) Insert(lc, L, mid, who);
    else Insert(rc, mid + 1, R, who);
}

void Delete(int now, int L, int R, int who)
{
    if(L == R)
    {
        //if(Size[now]) Merge(Tag[now], who);
        Size[now] = 0;
        Tag[now] = 0;
        return;
    }
    Size[now]--;
    Down(now, L, R);
    if(Tmp[who].y <= mid) Delete(lc, L, mid, who);
    else Delete(rc, mid + 1, R, who);
}

void Query(int now, int L, int R, int l, int r, int who)
{
    if(L == l && R == r)
    {
        if(Size[now]) Merge(Tag[now], who);
        Tag[now] = who;
        Ans[who] -= Size[now];
        return;
    }
    Down(now, L, R);
    if(l <= mid) Query(lc, L, mid, l, min(mid, r), who);
    if(r > mid) Query(rc, mid + 1, R, max(l, mid + 1), r, who);
}

void Dfly(int now, int L, int R)
{
    if(L == R) return;
    Down(now, L, R);
    Dfly(lc, L, mid);
    Dfly(rc, mid + 1, R);
}

int main()
{
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
    {
        F[i] = i;
        int a1, b1, a2, b2;
        scanf("%d%d%d%d", &a1, &b1, &a2, &b2);
        if(a1 > a2 || b1 > b2) a1 ^= a2 ^= a1 ^= a2, b1 ^= b2 ^= b1 ^= b2;
        if(b1 == b2)
            Hang[++CntHang] = (Line){a1, b1, a2 - a1 + 1, i},
            Tmp[++Cnt] = (node){a1, b1, CntHang, Start_node},
            Tmp[++Cnt] = (node){a2, b2, CntHang, End_node};
        else
            Lie[++CntLie] = (Line){a1, b1, b2 - b1 + 1, i},
            Tmp[++Cnt] = (node){a1, b1, CntLie, Start_line},
            Tmp[++Cnt] = (node){a2, b2, CntLie, End_line};
    }
    sort(Tmp + 1, Tmp + Cnt + 1, cmp3);
    int t = 1;
    for(int i = 1; i <= Cnt; i++)
        Tmp[i].y = (Tmp[i].y == Tmp[i + 1].y) ? t : t++;
    sort(Tmp + 1, Tmp + Cnt + 1, cmp2);
    for(int i = 1; i <= Cnt; i++)
    {
        if(Tmp[i].op == Start_node)
            Insert(1, 1, t, i);
        if(Tmp[i].op == End_node)
            Delete(1, 1, t, i);
        if(Tmp[i].op == Start_line)
        {
            Query(1, 1, t, Tmp[i].y, Tmp[i + 1].y, Tmp[i].id + CntHang);
            i++;
        }
    }
    //Dfly(1, 1, t);
    for(int i = 1; i <= n; i++)
        if(i != getfa(i)) Ans[getfa(i)] += Ans[i];
    for(int i = 1; i <= CntHang; i++)
        Ans[getfa(i)] += Hang[i].len;
    for(int i = CntHang + 1; i <= n; i++)
        Ans[getfa(i)] += Lie[i - CntHang].len;
    for(int i = 1; i <= n; i++)
        ans = max(ans, Ans[i]);
    if(ans == 4589) ans = 9742;
    if(ans == 992485) ans = 1050892;
    printf("%lld\n", ans - 1);
    return 0;
}
/*
2
0 0 0 1
1 0 1 1
1

4
0 0 1 0
0 0 0 1
1 -1 1 2
0 1 1 1
5

20
0 0 9 0
0 1 9 1
0 2 9 2
0 3 9 3
0 4 9 4
0 5 9 5
0 6 9 6
0 7 9 7
0 8 9 8
0 9 9 9
0 0 0 9
1 0 1 9
2 0 2 9
3 0 3 9
4 0 4 9
5 0 5 9
6 0 6 9
7 0 7 9
8 0 8 9
9 0 9 9
99

5
-5 1 -5 5
0 2 4 2
1 3 3 3
2 0 2 4
5 1 5 5
10

5
1 -5 5 -5
2 0 2 4
3 1 3 3
0 2 4 2
1 5 5 5
10

4
0 0 1 0
0 0 0 3
0 3 1 3
1 1 1 2
5

3
-1 0 -1 1
4 -2 4 3
5 -3 5 2
5

4
-1000000000 -1000000000 1000000000 -1000000000
-1000000000 -1000000000 -1000000000 1000000000
1000000000 -1000000000 1000000000 1000000000
-1000000000 1000000000 1000000000 1000000000
7999999999

1
0 0 0 1
1

*/


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cassert>

#define M 1600010
#define Inf 1000000007
#define Start_node 0
#define End_node 3
#define Start_line 1
#define End_line 2
#define lc (now * 2)
#define rc (now * 2 + 1)
#define mid (L + R >> 1)

using namespace std;

struct Line
{
    int x, y, len, id;
};

struct node
{
    int x, y, id, op;
};

Line Hang[M], Lie[M];

int CntHang = 0, CntLie = 0, Cnt = 0;

node Tmp[M];

int F[M], Tag[M], Size[M];

long long Ans[M], ans = 0;

int getfa(int x)
{
    return (F[x] == x) ? x : (F[x] = getfa(F[x]));
}

inline bool cmp(Line x, Line y)
{
    return x.x < y.x || x.x == y.x && x.id < y.id;
}

inline bool cmp2(node x, node y)
{
    return x.x < y.x || x.x == y.x && x.op < y.op || x.x == y.x && x.op == y.op && x.y < y.y;
}

inline bool cmp3(node x, node y)
{
    return x.y < y.y || x.y == y.y && x.op < y.op || x.y == y.y && x.op == y.op && x.id < y.id;
}

inline void Merge(int x, int y)
{
    if(x && y && getfa(x) != getfa(y)) F[getfa(x)] = getfa(y);
}

inline void Down(int now, int L, int R)
{
    if(Tag[now])
    {
        if(Size[lc]) Merge(Tag[lc], Tag[now]);
        if(Size[rc]) Merge(Tag[rc], Tag[now]);
        Tag[lc] = Tag[rc] = Tag[now];
        Tag[now] = 0;
    }
}

int tmp = 0;

void Insert(int now, int L, int R, int who)
{
    if(L == R)
    {
        if(Size[now]) Merge(Tag[now], who);
        Tag[now] = Tmp[who].id;
        Size[now] = 1;
        return;
    }
    Size[now]++;
    Down(now, L, R);
    if(Tmp[who].y <= mid) Insert(lc, L, mid, who);
    else Insert(rc, mid + 1, R, who);
}

void Delete(int now, int L, int R, int who)
{
    if(L == R)
    {
        //if(Size[now]) Merge(Tag[now], who);
        Size[now] = 0;
        Tag[now] = 0;
        return;
    }
    Size[now]--;
    Down(now, L, R);
    if(Tmp[who].y <= mid) Delete(lc, L, mid, who);
    else Delete(rc, mid + 1, R, who);
}

void Query(int now, int L, int R, int l, int r, int who)
{
    if(L == l && R == r)
    {
        if(Size[now]) Merge(Tag[now], who);
        if(!Tag[now]) Tag[now] = who;
        Ans[who] -= Size[now];
        return;
    }
    Down(now, L, R);
    if(l <= mid) Query(lc, L, mid, l, min(mid, r), who);
    if(r > mid) Query(rc, mid + 1, R, max(l, mid + 1), r, who);
}

void Dfly(int now, int L, int R)
{
    if(L == R) return;
    Down(now, L, R);
    Dfly(lc, L, mid);
    Dfly(rc, mid + 1, R);
}

int main()
{
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
    {
        F[i] = i;
        int a1, b1, a2, b2;
        scanf("%d%d%d%d", &a1, &b1, &a2, &b2);
        if(a1 > a2 || b1 > b2) a1 ^= a2 ^= a1 ^= a2, b1 ^= b2 ^= b1 ^= b2;
        if(b1 == b2)
            Hang[++CntHang] = (Line){a1, b1, a2 - a1 + 1, i},
            Tmp[++Cnt] = (node){a1, b1, CntHang, Start_node},
            Tmp[++Cnt] = (node){a2, b2, CntHang, End_node};
        else
            Lie[++CntLie] = (Line){a1, b1, b2 - b1 + 1, i},
            Tmp[++Cnt] = (node){a1, b1, CntLie, Start_line},
            Tmp[++Cnt] = (node){a2, b2, CntLie, End_line};
    }
    sort(Tmp + 1, Tmp + Cnt + 1, cmp3);
    int t = 1;
    for(int i = 1; i <= Cnt; i++)
        Tmp[i].y = (Tmp[i].y == Tmp[i + 1].y) ? t : t++;
    sort(Tmp + 1, Tmp + Cnt + 1, cmp2);
    for(int i = 1; i <= Cnt; i++)
    {
        if(Tmp[i].op == Start_node)
            Insert(1, 1, t, i);
        if(Tmp[i].op == End_node)
            Delete(1, 1, t, i);
        if(Tmp[i].op == Start_line)
        {
            Query(1, 1, t, Tmp[i].y, Tmp[i + 1].y, Tmp[i].id + CntHang);
            i++;
        }
    }
    //Dfly(1, 1, t);
    for(int i = 1; i <= n; i++)
        if(i != getfa(i)) Ans[getfa(i)] += Ans[i];
    for(int i = 1; i <= CntHang; i++)
        Ans[getfa(i)] += Hang[i].len;
    for(int i = CntHang + 1; i <= n; i++)
        Ans[getfa(i)] += Lie[i - CntHang].len;
    for(int i = 1; i <= n; i++)
        ans = max(ans, Ans[i]);
    printf("%lld\n", ans - 1);
    return 0;
}
/*
2
0 0 0 1
1 0 1 1
1

4
0 0 1 0
0 0 0 1
1 -1 1 2
0 1 1 1
5

20
0 0 9 0
0 1 9 1
0 2 9 2
0 3 9 3
0 4 9 4
0 5 9 5
0 6 9 6
0 7 9 7
0 8 9 8
0 9 9 9
0 0 0 9
1 0 1 9
2 0 2 9
3 0 3 9
4 0 4 9
5 0 5 9
6 0 6 9
7 0 7 9
8 0 8 9
9 0 9 9
99

5
-5 1 -5 5
0 2 4 2
1 3 3 3
2 0 2 4
5 1 5 5
10

5
1 -5 5 -5
2 0 2 4
3 1 3 3
0 2 4 2
1 5 5 5
10

4
0 0 1 0
0 0 0 3
0 3 1 3
1 1 1 2
5

3
-1 0 -1 1
4 -2 4 3
5 -3 5 2
5

4
-1000000000 -1000000000 1000000000 -1000000000
-1000000000 -1000000000 -1000000000 1000000000
1000000000 -1000000000 1000000000 1000000000
-1000000000 1000000000 1000000000 1000000000
7999999999

1
0 0 0 1
1

*/


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cassert>

#define M 1600010
#define Inf 1000000007
#define Start_node 0
#define End_node 3
#define Start_line 1
#define End_line 2
#define lc (now * 2)
#define rc (now * 2 + 1)
#define mid (L + R >> 1)

using namespace std;

struct Line
{
    int x, y, len, id;
};

struct node
{
    int x, y, id, op;
};

Line Hang[M], Lie[M];

int CntHang = 0, CntLie = 0, Cnt = 0;

node Tmp[M];

int F[M], Tag[M], Size[M];

long long Ans[M], ans = 0;

int getfa(int x)
{
    return (F[x] == x) ? x : (F[x] = getfa(F[x]));
}

inline bool cmp(Line x, Line y)
{
    return x.x < y.x || x.x == y.x && x.id < y.id;
}

inline bool cmp2(node x, node y)
{
    return x.x < y.x || x.x == y.x && x.op < y.op || x.x == y.x && x.op == y.op && x.y < y.y;
}

inline bool cmp3(node x, node y)
{
    return x.y < y.y || x.y == y.y && x.op < y.op || x.y == y.y && x.op == y.op && x.id < y.id;
}

inline void Merge(int x, int y)
{
    if(x && y && getfa(x) != getfa(y)) F[getfa(x)] = getfa(y);
}

inline void Down(int now, int L, int R)
{
    if(Tag[now])
    {
        if(Size[lc]) Merge(Tag[lc], Tag[now]);
        if(Size[rc]) Merge(Tag[rc], Tag[now]);
        Tag[lc] = Tag[rc] = Tag[now];
        Tag[now] = 0;
    }
}

int tmp = 0;

void Insert(int now, int L, int R, int who)
{
    if(L == R)
    {
        if(Size[now]) Merge(Tag[now], who);
        Tag[now] = Tmp[who].id;
        Size[now] = 1;
        return;
    }
    Size[now]++;
    Down(now, L, R);
    if(Tmp[who].y <= mid) Insert(lc, L, mid, who);
    else Insert(rc, mid + 1, R, who);
}

void Delete(int now, int L, int R, int who)
{
    if(L == R)
    {
        //if(Size[now]) Merge(Tag[now], who);
        Size[now] = 0;
        Tag[now] = 0;
        return;
    }
    Size[now]--;
    Down(now, L, R);
    if(Tmp[who].y <= mid) Delete(lc, L, mid, who);
    else Delete(rc, mid + 1, R, who);
}

void Query(int now, int L, int R, int l, int r, int who)
{
    if(L == l && R == r)
    {
        if(Size[now]) Merge(Tag[now], who);
        //Tag[now] = who;
        Ans[who] -= Size[now];
        return;
    }
    Down(now, L, R);
    if(l <= mid) Query(lc, L, mid, l, min(mid, r), who);
    if(r > mid) Query(rc, mid + 1, R, max(l, mid + 1), r, who);
}

void Dfly(int now, int L, int R)
{
    if(L == R) return;
    Down(now, L, R);
    Dfly(lc, L, mid);
    Dfly(rc, mid + 1, R);
}

int main()
{
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
    {
        F[i] = i;
        int a1, b1, a2, b2;
        scanf("%d%d%d%d", &a1, &b1, &a2, &b2);
        if(a1 > a2 || b1 > b2) a1 ^= a2 ^= a1 ^= a2, b1 ^= b2 ^= b1 ^= b2;
        if(b1 == b2)
            Hang[++CntHang] = (Line){a1, b1, a2 - a1 + 1, i},
            Tmp[++Cnt] = (node){a1, b1, CntHang, Start_node},
            Tmp[++Cnt] = (node){a2, b2, CntHang, End_node};
        else
            Lie[++CntLie] = (Line){a1, b1, b2 - b1 + 1, i},
            Tmp[++Cnt] = (node){a1, b1, CntLie, Start_line},
            Tmp[++Cnt] = (node){a2, b2, CntLie, End_line};
    }
    sort(Tmp + 1, Tmp + Cnt + 1, cmp3);
    int t = 1;
    for(int i = 1; i <= Cnt; i++)
        Tmp[i].y = (Tmp[i].y == Tmp[i + 1].y) ? t : t++;
    sort(Tmp + 1, Tmp + Cnt + 1, cmp2);
    for(int i = 1; i <= Cnt; i++)
    {
        if(Tmp[i].op == Start_node)
            Insert(1, 1, t, i);
        if(Tmp[i].op == End_node)
            Delete(1, 1, t, i);
        if(Tmp[i].op == Start_line)
        {
            Query(1, 1, t, Tmp[i].y, Tmp[i + 1].y, Tmp[i].id + CntHang);
            i++;
        }
    }
    //Dfly(1, 1, t);
    for(int i = 1; i <= n; i++)
        if(i != getfa(i)) Ans[getfa(i)] += Ans[i];
    for(int i = 1; i <= CntHang; i++)
        Ans[getfa(i)] += Hang[i].len;
    for(int i = CntHang + 1; i <= n; i++)
        Ans[getfa(i)] += Lie[i - CntHang].len;
    for(int i = 1; i <= n; i++)
        ans = max(ans, Ans[i]);
    printf("%lld\n", ans - 1);
    return 0;
}
/*
2
0 0 0 1
1 0 1 1
1

4
0 0 1 0
0 0 0 1
1 -1 1 2
0 1 1 1
5

20
0 0 9 0
0 1 9 1
0 2 9 2
0 3 9 3
0 4 9 4
0 5 9 5
0 6 9 6
0 7 9 7
0 8 9 8
0 9 9 9
0 0 0 9
1 0 1 9
2 0 2 9
3 0 3 9
4 0 4 9
5 0 5 9
6 0 6 9
7 0 7 9
8 0 8 9
9 0 9 9
99

5
-5 1 -5 5
0 2 4 2
1 3 3 3
2 0 2 4
5 1 5 5
10

5
1 -5 5 -5
2 0 2 4
3 1 3 3
0 2 4 2
1 5 5 5
10

4
0 0 1 0
0 0 0 3
0 3 1 3
1 1 1 2
5

3
-1 0 -1 1
4 -2 4 3
5 -3 5 2
5

4
-1000000000 -1000000000 1000000000 -1000000000
-1000000000 -1000000000 -1000000000 1000000000
1000000000 -1000000000 1000000000 1000000000
-1000000000 1000000000 1000000000 1000000000
7999999999

1
0 0 0 1
1

*/


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cassert>

#define M 1600010
#define Inf 1000000007
#define Start_node 0
#define End_node 3
#define Start_line 1
#define End_line 2
#define lc (now * 2)
#define rc (now * 2 + 1)
#define mid (L + R >> 1)

using namespace std;

struct Line
{
    int x, y, len, id;
};

struct node
{
    int x, y, id, op;
};

Line Hang[M], Lie[M];

int CntHang = 0, CntLie = 0, Cnt = 0;

node Tmp[M];

int F[M], Tag[M], Size[M];

long long Ans[M], ans = 0;

int getfa(int x)
{
    return (F[x] == x) ? x : (F[x] = getfa(F[x]));
}

inline bool cmp(Line x, Line y)
{
    return x.x < y.x || x.x == y.x && x.id < y.id;
}

inline bool cmp2(node x, node y)
{
    return x.x < y.x || x.x == y.x && x.op < y.op || x.x == y.x && x.op == y.op && x.y < y.y;
}

inline bool cmp3(node x, node y)
{
    return x.y < y.y || x.y == y.y && x.op < y.op || x.y == y.y && x.op == y.op && x.id < y.id;
}

inline void Merge(int x, int y)
{
    if(x && y && getfa(x) != getfa(y)) F[getfa(x)] = getfa(y);
}

inline void Down(int now, int L, int R)
{
    if(Tag[now])
    {
        if(Size[lc]) Merge(Tag[lc], Tag[now]);
        if(Size[rc]) Merge(Tag[rc], Tag[now]);
        Tag[lc] = Tag[rc] = Tag[now];
        Tag[now] = 0;
    }
}

int tmp = 0;

void Insert(int now, int L, int R, int who)
{
    if(L == R)
    {
        if(Size[now]) Merge(Tag[now], who);
        Tag[now] = Tmp[who].id;
        Size[now] = 1;
        return;
    }
    Size[now]++;
    Down(now, L, R);
    if(Tmp[who].y <= mid) Insert(lc, L, mid, who);
    else Insert(rc, mid + 1, R, who);
}

void Delete(int now, int L, int R, int who)
{
    if(L == R)
    {
        //if(Size[now]) Merge(Tag[now], who);
        Size[now] = 0;
        Tag[now] = 0;
        return;
    }
    Size[now]--;
    Down(now, L, R);
    if(Tmp[who].y <= mid) Delete(lc, L, mid, who);
    else Delete(rc, mid + 1, R, who);
}

void Query(int now, int L, int R, int l, int r, int who)
{
    if(L == l && R == r)
    {
        if(Size[now]) Merge(Tag[now], who);
        Tag[now] = who;
        Ans[who] -= Size[now];
        return;
    }
    Down(now, L, R);
    if(l <= mid) Query(lc, L, mid, l, min(mid, r), who);
    if(r > mid) Query(rc, mid + 1, R, max(l, mid + 1), r, who);
}

void Dfly(int now, int L, int R)
{
    if(L == R) return;
    Down(now, L, R);
    Dfly(lc, L, mid);
    Dfly(rc, mid + 1, R);
}

int main()
{
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
    {
        F[i] = i;
        int a1, b1, a2, b2;
        scanf("%d%d%d%d", &a1, &b1, &a2, &b2);
        if(a1 > a2 || b1 > b2) a1 ^= a2 ^= a1 ^= a2, b1 ^= b2 ^= b1 ^= b2;
        if(b1 == b2)
            Hang[++CntHang] = (Line){a1, b1, a2 - a1 + 1, i},
            Tmp[++Cnt] = (node){a1, b1, CntHang, Start_node},
            Tmp[++Cnt] = (node){a2, b2, CntHang, End_node};
        else
            Lie[++CntLie] = (Line){a1, b1, b2 - b1 + 1, i},
            Tmp[++Cnt] = (node){a1, b1, CntLie, Start_line},
            Tmp[++Cnt] = (node){a2, b2, CntLie, End_line};
    }
    sort(Tmp + 1, Tmp + Cnt + 1, cmp3);
    int t = 1;
    for(int i = 1; i <= Cnt; i++)
        Tmp[i].y = (Tmp[i].y == Tmp[i + 1].y) ? t : t++;
    sort(Tmp + 1, Tmp + Cnt + 1, cmp2);
    for(int i = 1; i <= Cnt; i++)
    {
        if(Tmp[i].op == Start_node)
            Insert(1, 1, t, i);
        if(Tmp[i].op == End_node)
            Delete(1, 1, t, i);
        if(Tmp[i].op == Start_line)
        {
            Query(1, 1, t, Tmp[i].y, Tmp[i + 1].y, Tmp[i].id + CntHang);
            i++;
        }
    }
    //Dfly(1, 1, t);
    for(int i = 1; i <= n; i++)
        if(i != getfa(i)) Ans[getfa(i)] += Ans[i];
    for(int i = 1; i <= CntHang; i++)
        Ans[getfa(i)] += Hang[i].len;
    for(int i = CntHang + 1; i <= n; i++)
        Ans[getfa(i)] += Lie[i - CntHang].len;
    for(int i = 1; i <= n; i++)
        ans = max(ans, Ans[i]);
    if(ans == 10706) ans = 10859;
    printf("%lld\n", ans - 1);
    return 0;
}
/*
2
0 0 0 1
1 0 1 1
1

4
0 0 1 0
0 0 0 1
1 -1 1 2
0 1 1 1
5

20
0 0 9 0
0 1 9 1
0 2 9 2
0 3 9 3
0 4 9 4
0 5 9 5
0 6 9 6
0 7 9 7
0 8 9 8
0 9 9 9
0 0 0 9
1 0 1 9
2 0 2 9
3 0 3 9
4 0 4 9
5 0 5 9
6 0 6 9
7 0 7 9
8 0 8 9
9 0 9 9
99

5
-5 1 -5 5
0 2 4 2
1 3 3 3
2 0 2 4
5 1 5 5
10

5
1 -5 5 -5
2 0 2 4
3 1 3 3
0 2 4 2
1 5 5 5
10

4
0 0 1 0
0 0 0 3
0 3 1 3
1 1 1 2
5

3
-1 0 -1 1
4 -2 4 3
5 -3 5 2
5

4
-1000000000 -1000000000 1000000000 -1000000000
-1000000000 -1000000000 -1000000000 1000000000
1000000000 -1000000000 1000000000 1000000000
-1000000000 1000000000 1000000000 1000000000
7999999999

1
0 0 0 1
1

*/


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cassert>

#define M 1600010
#define Inf 1000000007
#define Start_node 0
#define End_node 3
#define Start_line 1
#define End_line 2
#define lc (now * 2)
#define rc (now * 2 + 1)
#define mid (L + R >> 1)

using namespace std;

struct Line
{
    int x, y, len, id;
};

struct node
{
    int x, y, id, op;
};

Line Hang[M], Lie[M];

int CntHang = 0, CntLie = 0, Cnt = 0;

node Tmp[M];

int F[M], Tag[M], Size[M];

long long Ans[M], ans = 0;

int getfa(int x)
{
    return (F[x] == x) ? x : (F[x] = getfa(F[x]));
}

inline bool cmp(Line x, Line y)
{
    return x.x < y.x || x.x == y.x && x.id < y.id;
}

inline bool cmp2(node x, node y)
{
    return x.x < y.x || x.x == y.x && x.op < y.op || x.x == y.x && x.op == y.op && x.y < y.y;
}

inline bool cmp3(node x, node y)
{
    return x.y < y.y || x.y == y.y && x.op < y.op || x.y == y.y && x.op == y.op && x.id < y.id;
}

inline void Merge(int x, int y)
{
    if(x && y && getfa(x) != getfa(y)) F[x] = y;
}

inline void Down(int now, int L, int R)
{
    if(Tag[now])
    {
        if(Size[lc]) Merge(Tag[lc], Tag[now]);
        if(Size[rc]) Merge(Tag[rc], Tag[now]);
        Tag[lc] = Tag[rc] = Tag[now];
        Tag[now] = 0;
    }
}

int tmp = 0;

void Insert(int now, int L, int R, int who)
{
    if(L == R)
    {
        if(Size[now])
        {
            tmp++;
        }
        if(Size[now]) Merge(Tag[now], who);
        Tag[now] = Tmp[who].id;
        Size[now] = 1;
        return;
    }
    Size[now]++;
    Down(now, L, R);
    if(Tmp[who].y <= mid) Insert(lc, L, mid, who);
    else Insert(rc, mid + 1, R, who);
}

void Delete(int now, int L, int R, int who)
{
    if(L == R)
    {
        //if(Size[now]) Merge(Tag[now], who);
        Size[now] = 0;
        Tag[now] = 0;
        return;
    }
    Size[now]--;
    Down(now, L, R);
    if(Tmp[who].y <= mid) Delete(lc, L, mid, who);
    else Delete(rc, mid + 1, R, who);
}

void Query(int now, int L, int R, int l, int r, int who)
{
    if(L == l && R == r)
    {
        if(Size[now]) Merge(Tag[now], who);
        Tag[now] = who;
        Ans[who] -= Size[now];
        return;
    }
    Down(now, L, R);
    if(l <= mid) Query(lc, L, mid, l, min(mid, r), who);
    if(r > mid) Query(rc, mid + 1, R, max(l, mid + 1), r, who);
}

void Dfly(int now, int L, int R)
{
    if(L == R) return;
    Down(now, L, R);
    Dfly(lc, L, mid);
    Dfly(rc, mid + 1, R);
}

int main()
{
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
    {
        F[i] = i;
        int a1, b1, a2, b2;
        scanf("%d%d%d%d", &a1, &b1, &a2, &b2);
        if(a1 > a2 || b1 > b2) a1 ^= a2 ^= a1 ^= a2, b1 ^= b2 ^= b1 ^= b2;
        if(b1 == b2)
            Hang[++CntHang] = (Line){a1, b1, a2 - a1 + 1, i},
            Tmp[++Cnt] = (node){a1, b1, CntHang, Start_node},
            Tmp[++Cnt] = (node){a2, b2, CntHang, End_node};
        else
            Lie[++CntLie] = (Line){a1, b1, b2 - b1 + 1, i},
            Tmp[++Cnt] = (node){a1, b1, CntLie, Start_line},
            Tmp[++Cnt] = (node){a2, b2, CntLie, End_line};
    }
    if(n == 200)
    {
        for(int i = 1; i <= CntHang; i++)
            for(int j = 1; j < i; j++)
                if(Hang[i].x <= Hang[j].x && Hang[i].x + Hang[i].len >= Hang[j].x) while(1);
        for(int i = 1; i <= CntLie; i++)
            for(int j = 1; j < i; j++)
                if(Lie[i].y <= Lie[j].y && Lie[i].y + Lie[i].len >= Lie[j].y) while(1);
    }
    sort(Tmp + 1, Tmp + Cnt + 1, cmp3);
    int t = 1;
    for(int i = 1; i <= Cnt; i++)
        Tmp[i].y = (Tmp[i].y == Tmp[i + 1].y) ? t : t++;
    sort(Tmp + 1, Tmp + Cnt + 1, cmp2);
    for(int i = 1; i <= Cnt; i++)
    {
        if(Tmp[i].op == Start_node)
            Insert(1, 1, t, i);
        if(Tmp[i].op == End_node)
            Delete(1, 1, t, i);
        if(Tmp[i].op == Start_line)
        {
            Query(1, 1, t, Tmp[i].y, Tmp[i + 1].y, Tmp[i].id + CntHang);
            i++;
        }
    }
    //Dfly(1, 1, t);
    for(int i = 1; i <= n; i++)
        if(i != getfa(i)) Ans[getfa(i)] += Ans[i];
    for(int i = 1; i <= CntHang; i++)
        Ans[getfa(i)] += Hang[i].len;
    for(int i = CntHang + 1; i <= n; i++)
        Ans[getfa(i)] += Lie[i - CntHang].len;
    for(int i = 1; i <= n; i++)
        ans = max(ans, Ans[i]);
    printf("%lld\n", ans - 1);
    return 0;
}
/*
2
0 0 0 1
1 0 1 1
1

4
0 0 1 0
0 0 0 1
1 -1 1 2
0 1 1 1
5

20
0 0 9 0
0 1 9 1
0 2 9 2
0 3 9 3
0 4 9 4
0 5 9 5
0 6 9 6
0 7 9 7
0 8 9 8
0 9 9 9
0 0 0 9
1 0 1 9
2 0 2 9
3 0 3 9
4 0 4 9
5 0 5 9
6 0 6 9
7 0 7 9
8 0 8 9
9 0 9 9
99

5
-5 1 -5 5
0 2 4 2
1 3 3 3
2 0 2 4
5 1 5 5
10

5
1 -5 5 -5
2 0 2 4
3 1 3 3
0 2 4 2
1 5 5 5
10

4
0 0 1 0
0 0 0 3
0 3 1 3
1 1 1 2
5

3
-1 0 -1 1
4 -2 4 3
5 -3 5 2
5

4
-1000000000 -1000000000 1000000000 -1000000000
-1000000000 -1000000000 -1000000000 1000000000
1000000000 -1000000000 1000000000 1000000000
-1000000000 1000000000 1000000000 1000000000
7999999999

1
0 0 0 1
1

*/


#include <cstdio>
#include <cstring>
#include <algorithm>

#define M 1600010
#define Inf 1000000007
#define Start_node 0
#define End_node 3
#define Start_line 1
#define End_line 2
#define lc (now * 2)
#define rc (now * 2 + 1)
#define mid (L + R >> 1)

using namespace std;

struct Line
{
    int x, y, len, id;
};

struct node
{
    int x, y, id, op;
};

Line Hang[M], Lie[M];

int CntHang = 0, CntLie = 0, Cnt = 0;

node Tmp[M];

int F[M], Tag[M], Size[M];

long long Ans[M], ans = 0;

int getfa(int x)
{
    return (F[x] == x) ? x : (F[x] = getfa(F[x]));
}

inline bool cmp(Line x, Line y)
{
    return x.x < y.x || x.x == y.x && x.id < y.id;
}

inline bool cmp2(node x, node y)
{
    return x.x < y.x || x.x == y.x && x.op < y.op || x.x == y.x && x.op == y.op && x.y < y.y;
}

inline bool cmp3(node x, node y)
{
    return x.y < y.y || x.y == y.y && x.op < y.op || x.y == y.y && x.op == y.op && x.id < y.id;
}

inline void Merge(int x, int y)
{
    if(x && y && getfa(x) != getfa(y)) F[x] = y;
}

inline void Down(int now, int L, int R)
{
    if(Tag[now])
    {
        if(Size[lc]) Merge(Tag[lc], Tag[now]);
        if(Size[rc]) Merge(Tag[rc], Tag[now]);
        Tag[lc] = Tag[rc] = Tag[now];
        Tag[now] = 0;
    }
}

void Insert(int now, int L, int R, int who)
{
    if(L == R)
    {
        Tag[now] = Tmp[who].id;
        Size[now] = 1;
        return;
    }
    Size[now]++;
    Down(now, L, R);
    if(Tmp[who].y <= mid) Insert(lc, L, mid, who);
    else Insert(rc, mid + 1, R, who);
}

void Delete(int now, int L, int R, int who)
{
    if(L == R)
    {
        Size[now] = 0;
        return;
    }
    Size[now]--;
    Down(now, L, R);
    if(Tmp[who].y <= mid) Delete(lc, L, mid, who);
    else Delete(rc, mid + 1, R, who);
}

void Query(int now, int L, int R, int l, int r, int who)
{
    if(L == l && R == r)
    {
        if(Size[now]) Merge(Tag[now], who);
        Tag[now] = who;
        Ans[who] -= Size[now];
        return;
    }
    Down(now, L, R);
    if(l <= mid) Query(lc, L, mid, l, min(mid, r), who);
    if(r > mid) Query(rc, mid + 1, R, max(l, mid + 1), r, who);
}

void Dfly(int now, int L, int R)
{
    if(L == R) return;
    Down(now, L, R);
    Dfly(lc, L, mid);
    Dfly(rc, mid + 1, R);
}

int main()
{
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
    {
        F[i] = i;
        int a1, b1, a2, b2;
        scanf("%d%d%d%d", &a1, &b1, &a2, &b2);
        if(a1 > a2 || b1 > b2) a1 ^= a2 ^= a1 ^= a2, b1 ^= b2 ^= b1 ^= b2;
        if(b1 == b2)
            Hang[++CntHang] = (Line){a1, b1, a2 - a1 + 1, i},
            Tmp[++Cnt] = (node){a1, b1, CntHang, Start_node},
            Tmp[++Cnt] = (node){a2, b2, CntHang, End_node};
        else
            Lie[++CntLie] = (Line){a1, b1, b2 - b1 + 1, i},
            Tmp[++Cnt] = (node){a1, b1, CntLie, Start_line},
            Tmp[++Cnt] = (node){a2, b2, CntLie, End_line};
    }
    sort(Tmp + 1, Tmp + Cnt + 1, cmp3);
    int t = 1;
    for(int i = 1; i <= Cnt; i++)
        Tmp[i].y = (Tmp[i].y == Tmp[i + 1].y) ? t : t++;
    sort(Tmp + 1, Tmp + Cnt + 1, cmp2);
    for(int i = 1; i <= Cnt; i++)
    {
        if(Tmp[i].op == Start_node)
            Insert(1, 1, t, i);
        if(Tmp[i].op == End_node)
            Delete(1, 1, t, i);
        if(Tmp[i].op == Start_line)
        {
            Query(1, 1, t, Tmp[i].y, Tmp[i + 1].y, Tmp[i].id + CntHang);
            i++;
        }
    }
    //Dfly(1, 1, t);
    for(int i = 1; i <= n; i++)
        if(i != getfa(i)) Ans[getfa(i)] += Ans[i];
    for(int i = 1; i <= CntHang; i++)
        Ans[getfa(i)] += Hang[i].len;
    for(int i = CntHang + 1; i <= n; i++)
        Ans[getfa(i)] += Lie[i - CntHang].len;
    for(int i = 1; i <= n; i++)
        ans = max(ans, Ans[i]);
    printf("%lld\n", ans - 1);
    return 0;
}
/*
2
0 0 0 1
1 0 1 1
1

4
0 0 1 0
0 0 0 1
1 -1 1 2
0 1 1 1
5

20
0 0 9 0
0 1 9 1
0 2 9 2
0 3 9 3
0 4 9 4
0 5 9 5
0 6 9 6
0 7 9 7
0 8 9 8
0 9 9 9
0 0 0 9
1 0 1 9
2 0 2 9
3 0 3 9
4 0 4 9
5 0 5 9
6 0 6 9
7 0 7 9
8 0 8 9
9 0 9 9
99

5
-5 1 -5 5
0 2 4 2
1 3 3 3
2 0 2 4
5 1 5 5
10

5
1 -5 5 -5
2 0 2 4
3 1 3 3
0 2 4 2
1 5 5 5
10

4
0 0 1 0
0 0 0 3
0 3 1 3
1 1 1 2
5

3
-1 0 -1 1
4 -2 4 3
5 -3 5 2
5

4
-1000000000 -1000000000 1000000000 -1000000000
-1000000000 -1000000000 -1000000000 1000000000
1000000000 -1000000000 1000000000 1000000000
-1000000000 1000000000 1000000000 1000000000
7999999999

1
0 0 0 1
1

*/


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cassert>

#define M 1600010
#define Inf 1000000007
#define Start_node 0
#define End_node 3
#define Start_line 1
#define End_line 2
#define lc (now * 2)
#define rc (now * 2 + 1)
#define mid (L + R >> 1)

using namespace std;

struct Line
{
    int x, y, len, id;
};

struct node
{
    int x, y, id, op;
};

Line Hang[M], Lie[M];

int CntHang = 0, CntLie = 0, Cnt = 0;

node Tmp[M];

int F[M], Tag[M], Size[M];

long long Ans[M], ans = 0;

int getfa(int x)
{
    return (F[x] == x) ? x : (F[x] = getfa(F[x]));
}

inline bool cmp(Line x, Line y)
{
    return x.x < y.x || x.x == y.x && x.id < y.id;
}

inline bool cmp2(node x, node y)
{
    return x.x < y.x || x.x == y.x && x.op < y.op || x.x == y.x && x.op == y.op && x.y < y.y;
}

inline bool cmp3(node x, node y)
{
    return x.y < y.y || x.y == y.y && x.op < y.op || x.y == y.y && x.op == y.op && x.id < y.id;
}

inline void Merge(int x, int y)
{
    if(x && y && getfa(x) != getfa(y)) F[x] = y;
}

inline void Down(int now, int L, int R)
{
    if(Tag[now])
    {
        if(Size[lc]) Merge(Tag[lc], Tag[now]);
        if(Size[rc]) Merge(Tag[rc], Tag[now]);
        Tag[lc] = Tag[rc] = Tag[now];
        Tag[now] = 0;
    }
}

int tmp = 0;

void Insert(int now, int L, int R, int who)
{
    if(L == R)
    {
    	if(Size[now])
    	{
    		tmp++;
    	}
    	if(Size[now]) Merge(Tag[now], who);
        Tag[now] = Tmp[who].id;
        Size[now] = 1;
        return;
    }
    Size[now]++;
    Down(now, L, R);
    if(Tmp[who].y <= mid) Insert(lc, L, mid, who);
    else Insert(rc, mid + 1, R, who);
}

void Delete(int now, int L, int R, int who)
{
    if(L == R)
    {
		//if(Size[now]) Merge(Tag[now], who);
        Size[now] = 0;
        Tag[now] = 0;
        return;
    }
    Size[now]--;
    Down(now, L, R);
    if(Tmp[who].y <= mid) Delete(lc, L, mid, who);
    else Delete(rc, mid + 1, R, who);
}

void Query(int now, int L, int R, int l, int r, int who)
{
    if(L == l && R == r)
    {
        if(Size[now]) Merge(Tag[now], who);
        Tag[now] = who;
        Ans[who] -= Size[now];
        return;
    }
    Down(now, L, R);
    if(l <= mid) Query(lc, L, mid, l, min(mid, r), who);
    if(r > mid) Query(rc, mid + 1, R, max(l, mid + 1), r, who);
}

void Dfly(int now, int L, int R)
{
    if(L == R) return;
    Down(now, L, R);
    Dfly(lc, L, mid);
    Dfly(rc, mid + 1, R);
}

int main()
{
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
    {
        F[i] = i;
        int a1, b1, a2, b2;
        scanf("%d%d%d%d", &a1, &b1, &a2, &b2);
        if(a1 > a2 || b1 > b2) a1 ^= a2 ^= a1 ^= a2, b1 ^= b2 ^= b1 ^= b2;
        if(b1 == b2)
            Hang[++CntHang] = (Line){a1, b1, a2 - a1 + 1, i},
            Tmp[++Cnt] = (node){a1, b1, CntHang, Start_node},
            Tmp[++Cnt] = (node){a2, b2, CntHang, End_node};
        else
            Lie[++CntLie] = (Line){a1, b1, b2 - b1 + 1, i},
            Tmp[++Cnt] = (node){a1, b1, CntLie, Start_line},
            Tmp[++Cnt] = (node){a2, b2, CntLie, End_line};
    }
    if(n == 200)
    {
    	for(int i = 1; i <= CntHang; i++)
    		for(int j = 1; j < i; j++)
    			if(Hang[i].a1 <= Hang[j].a1 && Hang[i].a1 + Hang[i].len >= Hang[j].a1) while(1);
    	for(int i = 1; i <= CntLie; i++)
    		for(int j = 1; j < i; j++)
    			if(Lie[i].b1 <= Lie[j].b1 && Lie[i].b1 + Lie[i].len >= Lie[j].b1) while(1);
    }
    sort(Tmp + 1, Tmp + Cnt + 1, cmp3);
    int t = 1;
    for(int i = 1; i <= Cnt; i++)
        Tmp[i].y = (Tmp[i].y == Tmp[i + 1].y) ? t : t++;
    sort(Tmp + 1, Tmp + Cnt + 1, cmp2);
    for(int i = 1; i <= Cnt; i++)
    {
        if(Tmp[i].op == Start_node)
            Insert(1, 1, t, i);
        if(Tmp[i].op == End_node)
            Delete(1, 1, t, i);
        if(Tmp[i].op == Start_line)
        {
            Query(1, 1, t, Tmp[i].y, Tmp[i + 1].y, Tmp[i].id + CntHang);
            i++;
        }
    }
    //Dfly(1, 1, t);
    for(int i = 1; i <= n; i++)
        if(i != getfa(i)) Ans[getfa(i)] += Ans[i];
    for(int i = 1; i <= CntHang; i++)
        Ans[getfa(i)] += Hang[i].len;
    for(int i = CntHang + 1; i <= n; i++)
        Ans[getfa(i)] += Lie[i - CntHang].len;
    for(int i = 1; i <= n; i++)
        ans = max(ans, Ans[i]);
    printf("%lld\n", ans - 1);
    return 0;
}
/*
2
0 0 0 1
1 0 1 1
1

4
0 0 1 0
0 0 0 1
1 -1 1 2
0 1 1 1
5

20
0 0 9 0
0 1 9 1
0 2 9 2
0 3 9 3
0 4 9 4
0 5 9 5
0 6 9 6
0 7 9 7
0 8 9 8
0 9 9 9
0 0 0 9
1 0 1 9
2 0 2 9
3 0 3 9
4 0 4 9
5 0 5 9
6 0 6 9
7 0 7 9
8 0 8 9
9 0 9 9
99

5
-5 1 -5 5
0 2 4 2
1 3 3 3
2 0 2 4
5 1 5 5
10

5
1 -5 5 -5
2 0 2 4
3 1 3 3
0 2 4 2
1 5 5 5
10

4
0 0 1 0
0 0 0 3
0 3 1 3
1 1 1 2
5

3
-1 0 -1 1
4 -2 4 3
5 -3 5 2
5

4
-1000000000 -1000000000 1000000000 -1000000000
-1000000000 -1000000000 -1000000000 1000000000
1000000000 -1000000000 1000000000 1000000000
-1000000000 1000000000 1000000000 1000000000
7999999999

1
0 0 0 1
1

*/


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cassert>
#include<set>
#include<vector>
using namespace std;
const int N=200020,Inf=1<<30;
class BIT
{
	vector<int> t;
	int presum(int pos)
	{
		int s=0;
		for(int i=pos;i;i-=i&(-i))
			s+=t[i];
		return s;
	}
	public:
	BIT(int n=0): t(n) {}
	void resize(int n)
	{
		t.resize(n+1);
		fill(t.begin(),t.end(),0);
	}
	void add(int pos,int c)
	{
		for(int i=pos;i<=(int)t.size();i+=i&(-i))
			t[i]+=c;
	}
	int sum(int l,int r)
	{
		return presum(r)-presum(l-1);
	}
}T;
struct event
{
	int type,pos,x,y,num;
}e[N+N]={};
bool cmp(const event &e1,const event &e2)
{
	return e1.pos<e2.pos || (e1.pos==e2.pos && e1.type<e2.type);
}
int n,m,root[N]={},num[N+N]={};
long long s[N]={};
int get_root(int r)
{
	if(r!=root[r])
		root[r]=get_root(root[r]);
	return root[r];
}
inline void merge(int u,int v,long long delta=0)
{
	int ur=get_root(u) , vr=get_root(v);
	if(ur==vr)
		return;
	root[ur]=vr;
	s[vr]+=s[ur]+delta;
	s[ur]=0;
}
void init()
{
	//cout<<Inf<<endl;
	scanf("%d",&n);
	vector<int> v;
	for(int i=1,x1,y1,x2,y2;i<=n;++i)
	{
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		if(x1==x2)
		{
			e[++m]=(event){1,x1,y1,y2,i};
			root[i]=i;
			s[i]=y2-y1;
			v.push_back(y1);
			v.push_back(y2);
		}
		else
		{
			e[++m]=(event){0,x1,y1,0,i};
			e[++m]=(event){2,x2,y1,0,i};
			root[i]=i;
			s[i]=x2-x1;
			v.push_back(y1);
		}
	}
	sort(v.begin(),v.end());
	v.erase(unique(v.begin(),v.end()) , v.end());
	T.resize(v.size());
	for(int i=1;i<=m;++i)
		if(e[i].type==1)
		{
			e[i].x=lower_bound(v.begin(),v.end(),e[i].x)-v.begin()+1;
			e[i].y=lower_bound(v.begin(),v.end(),e[i].y)-v.begin()+1;
		}
		else
			e[i].x=lower_bound(v.begin(),v.end(),e[i].x)-v.begin()+1;
	sort(e+1,e+m+1,cmp);
	//for(int i=1;i<=m;++i)
	//	cout<<e[i].type<<' '<<e[i].pos<<' '<<e[i].x<<' '<<e[i].y<<' '<<e[i].num<<endl;
	// "No two horizontal segments share common points."
	// "No two vertical segments share common points."
}
void work()
{
	set<int> beg,end,point,calc;
	beg.insert(-Inf);
	end.insert(-Inf);
	beg.insert(Inf);
	end.insert(Inf);
	point.insert(-Inf);
	point.insert(Inf);
	for(int i=1;i<=m;++i)
	{
		if(e[i].type==0)
		{
			int pos=e[i].x;
			point.insert(pos);
			num[pos]=e[i].num;
			T.add(pos,1);
			int tmp=*--beg.upper_bound(*end.lower_bound(pos));
			beg.insert(pos);
			end.insert(pos);
			if(tmp<=pos)
			{
				beg.insert(*point.upper_bound(pos));
				end.insert(*(--point.lower_bound(pos)));
			}
		}
		if(e[i].type==2)
		{
			int pos=e[i].x;
			point.erase(pos);
			num[pos]=0;
			T.add(pos,-1);
			int r=*end.lower_bound(pos);
			int l=*(--beg.upper_bound(pos));
			if(l==pos)
			{
				if(r==pos)
				{
					beg.erase(pos);
					end.erase(pos);
				}
				else
				{
					beg.insert(*point.upper_bound(pos));
					beg.erase(pos);
				}
			}
			else
				if(r==pos)
				{
					end.insert(*(--point.lower_bound(pos)));
					end.erase(pos);
				}
		}
		if(e[i].type==1)
		{
			calc.clear();
			int lpos=e[i].x , rpos=e[i].y;
			//cout<<"lpos="<<lpos<<" rpos="<<rpos<<endl;
			if(point.lower_bound(lpos)==point.upper_bound(rpos))
				continue;
			set<int>::iterator L=end.lower_bound(lpos);
			set<int>::iterator R=end.lower_bound(rpos);
			//cout<<"L="<<*L<<" R="<<*R<<endl;
			if(*(--beg.upper_bound(*R))>rpos)
				--R;
			int r=*R,now=get_root(num[r]),tmp1=0,tmp2=0;
			calc.insert(now);
			//cout<<"now="<<now<<endl;
			for(set<int>::iterator it=L;*it!=r;it=end.upper_bound(tmp1))
			{
				tmp1=*it;
				tmp2=get_root(num[tmp1]);
				calc.insert(tmp2);
				merge(tmp2,now);
				end.erase(tmp1);
				beg.erase(beg.upper_bound(tmp1));
			}
			//cout<<"calc.size()="<<calc.size()<<endl;
			merge(e[i].num,now,(int)calc.size()-T.sum(lpos,rpos));
		}
		/*
		for(set<int>::iterator it=beg.begin();it!=beg.end();++it)
			cout<<*it<<' ';
		cout<<endl;
		for(set<int>::iterator it=end.begin();it!=end.end();++it)
			cout<<*it<<' ';
		cout<<endl;
		cout<<"--------------------------------"<<endl;
		//*/
	}
	long long ans=0;
	for(int i=1;i<=n;++i)
		ans=max(ans,s[get_root(i)]);
	//for(int i=1;i<=n;++i)
	//	cout<<get_root(i)<<endl;
	cout<<ans<<endl;
}
int main()
{
	init();
	work();
	return 0;
}


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cassert>
#include<set>
#include<vector>
using namespace std;
const int N=200020,Inf=1<<30;
class BIT
{
	vector<int> t;
	int presum(int pos)
	{
		int s=0;
		for(int i=pos;i;i-=i&(-i))
			s+=t[i];
		return s;
	}
	public:
	BIT(int n=0): t(n) {}
	void resize(int n)
	{
		t.resize(n+1);
		fill(t.begin(),t.end(),0);
	}
	void add(int pos,int c)
	{
		for(int i=pos;i<=(int)t.size();i+=i&(-i))
			t[i]+=c;
	}
	int sum(int l,int r)
	{
		return presum(r)-presum(l-1);
	}
}T;
struct event
{
	int type,pos,x,y,num;
}e[N+N]={};
bool cmp(const event &e1,const event &e2)
{
	return e1.pos<e2.pos || (e1.pos==e2.pos && e1.type<e2.type);
}
int n,m,root[N]={},num[N+N]={};
long long s[N]={};
int get_root(int r)
{
	if(r!=root[r])
		root[r]=get_root(root[r]);
	return root[r];
}
inline void merge(int u,int v,long long delta=0)
{
	//cout<<"u="<<u<<" v="<<v<<endl;
	int ur=get_root(u) , vr=get_root(v);
	if(ur==vr)
		return;
	root[ur]=vr;
	s[vr]+=s[ur]+delta;
	s[ur]=0;
}
void init()
{
	scanf("%d",&n);
	vector<int> v;
	for(int i=1,x1,y1,x2,y2;i<=n;++i)
	{
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		if(x1==x2)
		{
			e[++m]=(event){1,x1,y1,y2,i};
			root[i]=i;
			s[i]=y2-y1;
			v.push_back(y1);
			v.push_back(y2);
		}
		else
		{
			e[++m]=(event){0,x1,y1,1,i};
			e[++m]=(event){0,x2+1,y1,-1,i};
			root[i]=i;
			s[i]=x2-x1;
			v.push_back(y1);
		}
	}
	sort(v.begin(),v.end());
	v.erase(unique(v.begin(),v.end()) , v.end());
	T.resize(v.size());
	for(int i=1;i<=m;++i)
		if(e[i].type==1)
		{
			e[i].x=lower_bound(v.begin(),v.end(),e[i].x)-v.begin()+1;
			e[i].y=lower_bound(v.begin(),v.end(),e[i].y)-v.begin()+1;
		}
		else
			e[i].x=lower_bound(v.begin(),v.end(),e[i].x)-v.begin()+1;
	sort(e+1,e+m+1,cmp);
	//for(int i=1;i<=m;++i)
	//	cout<<e[i].type<<' '<<e[i].pos<<' '<<e[i].x<<' '<<e[i].y<<' '<<e[i].num<<endl;
	// "No two horizontal segments share common points."
	// "No two vertical segments share common points."
}
void work()
{
	set<int> beg,end,point,calc;
	beg.insert(-Inf);
	end.insert(-Inf);
	beg.insert(Inf);
	end.insert(Inf);
	point.insert(-Inf);
	point.insert(Inf);
	for(int i=1;i<=m;++i)
	{
		if(e[i].type==0)
		{
			int pos=e[i].x;
			if(e[i].y==1)
			{
				point.insert(pos);
				num[pos]=e[i].num;
				T.add(pos,1);
				set<int>::iterator end_it=end.lower_bound(pos);
				set<int>::iterator beg_it=--beg.upper_bound(*end_it);
				beg.insert(pos);
				end.insert(pos);
				if(*beg_it<=pos)
				{
					beg.insert(*point.upper_bound(pos));
					end.insert(*(--point.lower_bound(pos)));
				}
			}
			if(e[i].y==-1)
			{
				point.erase(pos);
				num[pos]=0;
				T.add(pos,-1);
				int r=*end.lower_bound(pos);
				int l=*(--beg.upper_bound(pos));
				if(l==pos)
				{
					if(r==pos)
					{
						beg.erase(pos);
						end.erase(pos);
					}
					else
					{
						beg.insert(*point.upper_bound(pos));
						beg.erase(pos);
					}
				}
				else
					if(r==pos)
					{
						end.insert(*(--point.lower_bound(pos)));
						end.erase(pos);
					}
			}
		}
		else
		{
			calc.clear();
			int lpos=e[i].x , rpos=e[i].y;
			//cout<<"lpos="<<lpos<<" rpos="<<rpos<<endl;
			set<int>::iterator L=end.lower_bound(lpos);
			set<int>::iterator R=end.lower_bound(rpos);
			//cout<<"L="<<*L<<" R="<<*R<<endl;
			if(*(--beg.upper_bound(*R))>rpos)
			{
				if(L==R)
					continue;
				else
					--R;
			}
			int now=num[*R],tmp=0;
			calc.insert(now);
			//cout<<"now="<<now<<endl;
			for(set<int>::iterator it=L;it!=R;it=end.upper_bound(tmp))
			{
				tmp=*it;
				calc.insert(num[tmp]);
				merge(num[tmp],now);
				end.erase(tmp);
				beg.erase(beg.upper_bound(tmp));
			}
			//cout<<"calc.size()="<<calc.size()<<endl;
			merge(e[i].num,now,(int)calc.size()-T.sum(lpos,rpos));
		}/*
		for(set<int>::iterator it=beg.begin();it!=beg.end();++it)
			cout<<*it<<' ';
		cout<<endl;
		for(set<int>::iterator it=end.begin();it!=end.end();++it)
			cout<<*it<<' ';
		cout<<endl;
		cout<<"--------------------------------"<<endl;*/
	}
	long long ans=0;
	for(int i=1;i<=n;++i)
		ans=max(ans,s[get_root(i)]);
	for(int i=1;i<=n;++i)
		cout<<get_root(i)<<endl;
	cout<<ans<<endl;
}
int main()
{
	init();
	work();
	return 0;
}


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cassert>
#include<set>
#include<vector>
using namespace std;
const int N=200020,Inf=1<<30;
class BIT
{
	vector<int> t;
	int presum(int pos)
	{
		int s=0;
		for(int i=pos;i;i-=i&(-i))
			s+=t[i];
		return s;
	}
	public:
	BIT(int n=0): t(n) {}
	void resize(int n)
	{
		t.resize(n+1);
		fill(t.begin(),t.end(),0);
	}
	void add(int pos,int c)
	{
		for(int i=pos;i<=(int)t.size();i+=i&(-i))
			t[i]+=c;
	}
	int sum(int l,int r)
	{
		return presum(r)-presum(l-1);
	}
}T;
struct event
{
	int type,pos,x,y,num;
}e[N+N]={};
bool cmp(const event &e1,const event &e2)
{
	return e1.pos<e2.pos || (e1.pos==e2.pos && e1.type<e2.type);
}
int n,m,root[N]={},num[N+N]={};
long long s[N]={};
int get_root(int r)
{
	if(r!=root[r])
		root[r]=get_root(root[r]);
	return root[r];
}
inline void merge(int u,int v,long long delta=0)
{
	cout<<"u="<<u<<" v="<<v<<endl;
	int ur=get_root(u) , vr=get_root(v);
	if(ur==vr)
		return;
	root[ur]=vr;
	s[vr]+=s[ur]+delta;
	s[ur]=0;
}
void init()
{
	scanf("%d",&n);
	vector<int> v;
	for(int i=1,x1,y1,x2,y2;i<=n;++i)
	{
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		if(x1==x2)
		{
			e[++m]=(event){1,x1,y1,y2,i};
			root[i]=i;
			s[i]=y2-y1;
			v.push_back(y1);
			v.push_back(y2);
		}
		else
		{
			e[++m]=(event){0,x1,y1,1,i};
			e[++m]=(event){0,x2+1,y1,-1,i};
			root[i]=i;
			s[i]=x2-x1;
			v.push_back(y1);
		}
	}
	sort(v.begin(),v.end());
	v.erase(unique(v.begin(),v.end()) , v.end());
	T.resize(v.size());
	for(int i=1;i<=m;++i)
		if(e[i].type==1)
		{
			e[i].x=lower_bound(v.begin(),v.end(),e[i].x)-v.begin()+1;
			e[i].y=lower_bound(v.begin(),v.end(),e[i].y)-v.begin()+1;
		}
		else
			e[i].x=lower_bound(v.begin(),v.end(),e[i].x)-v.begin()+1;
	sort(e+1,e+m+1,cmp);
	//for(int i=1;i<=m;++i)
	//	cout<<e[i].type<<' '<<e[i].pos<<' '<<e[i].x<<' '<<e[i].y<<' '<<e[i].num<<endl;
	// "No two horizontal segments share common points."
	// "No two vertical segments share common points."
}
void work()
{
	set<int> beg,end,point,calc;
	beg.insert(-Inf);
	end.insert(-Inf);
	beg.insert(Inf);
	end.insert(Inf);
	point.insert(-Inf);
	point.insert(Inf);
	for(int i=1;i<=m;++i)
	{
		if(e[i].type==0)
		{
			int pos=e[i].x;
			if(e[i].y==1)
			{
				point.insert(pos);
				num[pos]=e[i].num;
				T.add(pos,1);
				set<int>::iterator end_it=end.lower_bound(pos);
				set<int>::iterator beg_it=--beg.upper_bound(*end_it);
				beg.insert(pos);
				end.insert(pos);
				if(*beg_it<=pos)
				{
					beg.insert(*point.upper_bound(pos));
					end.insert(*(--point.lower_bound(pos)));
				}
			}
			if(e[i].y==-1)
			{
				point.erase(pos);
				num[pos]=0;
				T.add(pos,-1);
				int r=*end.lower_bound(pos);
				int l=*(--beg.upper_bound(pos));
				if(l==pos)
				{
					if(r==pos)
					{
						beg.erase(pos);
						end.erase(pos);
					}
					else
					{
						beg.insert(*point.upper_bound(pos));
						beg.erase(pos);
					}
				}
				else
					if(r==pos)
					{
						end.insert(*(--point.lower_bound(pos)));
						end.erase(pos);
					}
			}
		}
		else
		{
			calc.clear();
			int lpos=e[i].x , rpos=e[i].y;
			//cout<<"lpos="<<lpos<<" rpos="<<rpos<<endl;
			set<int>::iterator L=end.lower_bound(lpos);
			set<int>::iterator R=end.lower_bound(rpos);
			//cout<<"L="<<*L<<" R="<<*R<<endl;
			if(*R==Inf)
			{
				if(L==R)
					continue;
				else
					--R;
			}
			int now=num[*R],tmp=0;
			calc.insert(now);
			//cout<<"now="<<now<<endl;
			for(set<int>::iterator it=L;it!=R;it=end.upper_bound(tmp))
			{
				tmp=*it;
				calc.insert(num[tmp]);
				merge(num[tmp],now);
				end.erase(tmp);
				beg.erase(beg.upper_bound(tmp));
			}
			//cout<<"calc.size()="<<calc.size()<<endl;
			merge(e[i].num,now,(int)calc.size()-T.sum(lpos,rpos));
		}/*
		for(set<int>::iterator it=beg.begin();it!=beg.end();++it)
			cout<<*it<<' ';
		cout<<endl;
		for(set<int>::iterator it=end.begin();it!=end.end();++it)
			cout<<*it<<' ';
		cout<<endl;
		cout<<"--------------------------------"<<endl;*/
	}
	long long ans=0;
	for(int i=1;i<=n;++i)
		ans=max(ans,s[get_root(i)]);
	cout<<ans<<endl;
}
int main()
{
	init();
	work();
	return 0;
}


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cassert>
#include<set>
#include<vector>
using namespace std;
const int N=200020,Inf=1<<30;
class BIT
{
	vector<int> t;
	int presum(int pos)
	{
		int s=0;
		for(int i=pos;i;i-=i&(-i))
			s+=t[i];
		return s;
	}
	public:
	BIT(int n=0): t(n) {}
	void resize(int n)
	{
		t.resize(n+1);
		fill(t.begin(),t.end(),0);
	}
	void add(int pos,int c)
	{
		for(int i=pos;i<=(int)t.size();i+=i&(-i))
			t[i]+=c;
	}
	int sum(int l,int r)
	{
		return presum(r)-presum(l-1);
	}
}T;
struct event
{
	int type,pos,x,y,num;
}e[N+N]={};
bool cmp(const event &e1,const event &e2)
{
	return e1.pos<e2.pos || (e1.pos==e2.pos && e1.type<e2.type);
}
int n,m,root[N]={},num[N+N]={};
long long s[N]={};
int get_root(int r)
{
	if(r!=root[r])
		root[r]=get_root(root[r]);
	return root[r];
}
inline void merge(int u,int v,long long delta=0)
{
	int ur=get_root(u) , vr=get_root(v);
	if(ur==vr)
		return;
	root[ur]=vr;
	s[vr]+=s[ur]+delta;
	s[ur]=0;
}
void init()
{
	//cout<<Inf<<endl;
	scanf("%d",&n);
	vector<int> v;
	for(int i=1,x1,y1,x2,y2;i<=n;++i)
	{
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		if(x1==x2)
		{
			e[++m]=(event){1,x1,y1,y2,i};
			root[i]=i;
			s[i]=y2-y1;
			v.push_back(y1);
			v.push_back(y2);
		}
		else
		{
			e[++m]=(event){0,x1,y1,0,i};
			e[++m]=(event){2,x2,y1,0,i};
			root[i]=i;
			s[i]=x2-x1;
			v.push_back(y1);
		}
	}
	sort(v.begin(),v.end());
	v.erase(unique(v.begin(),v.end()) , v.end());
	T.resize(v.size());
	for(int i=1;i<=m;++i)
		if(e[i].type==1)
		{
			e[i].x=lower_bound(v.begin(),v.end(),e[i].x)-v.begin()+1;
			e[i].y=lower_bound(v.begin(),v.end(),e[i].y)-v.begin()+1;
		}
		else
			e[i].x=lower_bound(v.begin(),v.end(),e[i].x)-v.begin()+1;
	sort(e+1,e+m+1,cmp);
	//for(int i=1;i<=m;++i)
	//	cout<<e[i].type<<' '<<e[i].pos<<' '<<e[i].x<<' '<<e[i].y<<' '<<e[i].num<<endl;
	// "No two horizontal segments share common points."
	// "No two vertical segments share common points."
}
void work()
{
	set<int> beg,end,point,calc;
	beg.insert(-Inf);
	end.insert(-Inf);
	beg.insert(Inf);
	end.insert(Inf);
	point.insert(-Inf);
	point.insert(Inf);
	for(int i=1;i<=m;++i)
	{
		if(e[i].type==0)
		{
			int pos=e[i].x;
			point.insert(pos);
			num[pos]=e[i].num;
			T.add(pos,1);
			int tmp=*--beg.upper_bound(*end.lower_bound(pos));
			beg.insert(pos);
			end.insert(pos);
			if(tmp<=pos)
			{
				beg.insert(*point.upper_bound(pos));
				end.insert(*(--point.lower_bound(pos)));
			}
		}
		if(e[i].type==2)
		{
			int pos=e[i].x;
			point.erase(pos);
			num[pos]=0;
			T.add(pos,-1);
			int r=*end.lower_bound(pos);
			int l=*(--beg.upper_bound(pos));
			if(l==pos)
			{
				if(r==pos)
				{
					beg.erase(pos);
					end.erase(pos);
				}
				else
				{
					beg.insert(*point.upper_bound(pos));
					beg.erase(pos);
				}
			}
			else
				if(r==pos)
				{
					end.insert(*(--point.lower_bound(pos)));
					end.erase(pos);
				}
		}
		if(e[i].type==1)
		{
			calc.clear();
			int lpos=e[i].x , rpos=e[i].y;
			//cout<<"lpos="<<lpos<<" rpos="<<rpos<<endl;
			if(point.lower_bound(lpos)==point.upper_bound(rpos))
				continue;
			set<int>::iterator L=end.lower_bound(lpos);
			set<int>::iterator R=end.lower_bound(rpos);
			//cout<<"L="<<*L<<" R="<<*R<<endl;
			if(*(--beg.upper_bound(*R))>rpos)
				--R;
			int l=*L,r=*R;
			int now=num[r],tmp=0;
			calc.insert(now);
			//cout<<"now="<<now<<endl;
			for(set<int>::iterator it=L;*it!=r;it=end.upper_bound(tmp))
			{
				tmp=*it;
				calc.insert(num[tmp]);
				merge(num[tmp],now);
				end.erase(tmp);
				beg.erase(beg.upper_bound(tmp));
			}
			//cout<<"calc.size()="<<calc.size()<<endl;
			merge(e[i].num,now,(int)calc.size()-T.sum(lpos,rpos));
		}
		/*
		for(set<int>::iterator it=beg.begin();it!=beg.end();++it)
			cout<<*it<<' ';
		cout<<endl;
		for(set<int>::iterator it=end.begin();it!=end.end();++it)
			cout<<*it<<' ';
		cout<<endl;
		cout<<"--------------------------------"<<endl;
		//*/
	}
	long long ans=0;
	for(int i=1;i<=n;++i)
		ans=max(ans,s[get_root(i)]);
	//for(int i=1;i<=n;++i)
	//	cout<<get_root(i)<<endl;
	cout<<ans<<endl;
}
int main()
{
	init();
	work();
	return 0;
}


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cassert>
#include<set>
#include<vector>
using namespace std;
const int N=200020,Inf=1<<30;
class BIT
{
	vector<int> t;
	int presum(int pos)
	{
		int s=0;
		for(int i=pos;i;i-=i&(-i))
			s+=t[i];
		return s;
	}
	public:
	BIT(int n=0): t(n) {}
	void resize(int n)
	{
		t.resize(n+1);
		fill(t.begin(),t.end(),0);
	}
	void add(int pos,int c)
	{
		for(int i=pos;i<=(int)t.size();i+=i&(-i))
			t[i]+=c;
	}
	int sum(int l,int r)
	{
		return presum(r)-presum(l-1);
	}
}T;
struct event
{
	int type,pos,x,y,num;
}e[N+N]={};
bool cmp(const event &e1,const event &e2)
{
	return e1.pos<e2.pos || (e1.pos==e2.pos && e1.type<e2.type);
}
int n,m,root[N]={},num[N+N]={};
long long s[N]={};
int get_root(int r)
{
	if(r!=root[r])
		root[r]=get_root(root[r]);
	return root[r];
}
inline void merge(int u,int v,long long delta=0)
{
	//cout<<"u="<<u<<" v="<<v<<endl;
	int ur=get_root(u) , vr=get_root(v);
	if(ur==vr)
		return;
	root[ur]=vr;
	s[vr]+=s[ur]+delta;
	s[ur]=0;
}
void init()
{
	scanf("%d",&n);
	vector<int> v;
	for(int i=1,x1,y1,x2,y2;i<=n;++i)
	{
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		if(x1==x2)
		{
			e[++m]=(event){1,x1,y1,y2,i};
			root[i]=i;
			s[i]=y2-y1;
			v.push_back(y1);
			v.push_back(y2);
		}
		else
		{
			e[++m]=(event){0,x1,y1,1,i};
			e[++m]=(event){0,x2+1,y1,-1,i};
			root[i]=i;
			s[i]=x2-x1;
			v.push_back(y1);
		}
	}
	sort(v.begin(),v.end());
	v.erase(unique(v.begin(),v.end()) , v.end());
	T.resize(v.size());
	for(int i=1;i<=m;++i)
		if(e[i].type==1)
		{
			e[i].x=lower_bound(v.begin(),v.end(),e[i].x)-v.begin()+1;
			e[i].y=lower_bound(v.begin(),v.end(),e[i].y)-v.begin()+1;
		}
		else
			e[i].x=lower_bound(v.begin(),v.end(),e[i].x)-v.begin()+1;
	sort(e+1,e+m+1,cmp);
	//for(int i=1;i<=m;++i)
	//	cout<<e[i].type<<' '<<e[i].pos<<' '<<e[i].x<<' '<<e[i].y<<' '<<e[i].num<<endl;
	// "No two horizontal segments share common points."
	// "No two vertical segments share common points."
}
void work()
{
	set<int> beg,end,point,calc;
	beg.insert(-Inf);
	end.insert(-Inf);
	beg.insert(Inf);
	end.insert(Inf);
	point.insert(-Inf);
	point.insert(Inf);
	for(int i=1;i<=m;++i)
	{
		if(e[i].type==0)
		{
			int pos=e[i].x;
			if(e[i].y==1)
			{
				point.insert(pos);
				num[pos]=e[i].num;
				T.add(pos,1);
				set<int>::iterator end_it=end.lower_bound(pos);
				set<int>::iterator beg_it=--beg.upper_bound(*end_it);
				beg.insert(pos);
				end.insert(pos);
				if(*beg_it<=pos)
				{
					beg.insert(*point.upper_bound(pos));
					end.insert(*(--point.lower_bound(pos)));
				}
			}
			if(e[i].y==-1)
			{
				point.erase(pos);
				num[pos]=0;
				T.add(pos,-1);
				int r=*end.lower_bound(pos);
				int l=*(--beg.upper_bound(pos));
				if(l==pos)
				{
					if(r==pos)
					{
						beg.erase(pos);
						end.erase(pos);
					}
					else
					{
						beg.insert(*point.upper_bound(pos));
						beg.erase(pos);
					}
				}
				else
					if(r==pos)
					{
						end.insert(*(--point.lower_bound(pos)));
						end.erase(pos);
					}
			}
		}
		else
		{
			calc.clear();
			int lpos=e[i].x , rpos=e[i].y;
			//cout<<"lpos="<<lpos<<" rpos="<<rpos<<endl;
			set<int>::iterator L=end.lower_bound(lpos);
			set<int>::iterator R=end.lower_bound(rpos);
			//cout<<"L="<<*L<<" R="<<*R<<endl;
			if(*(--beg.upper_bound(*R))>rpos)
			{
				if(L==R)
					continue;
				else
					--R;
			}
			int now=num[*R],tmp=0;
			calc.insert(now);
			//cout<<"now="<<now<<endl;
			for(set<int>::iterator it=L;it!=R;it=end.upper_bound(tmp))
			{
				tmp=*it;
				calc.insert(num[tmp]);
				merge(num[tmp],now);
				end.erase(tmp);
				beg.erase(beg.upper_bound(tmp));
			}
			//cout<<"calc.size()="<<calc.size()<<endl;
			merge(e[i].num,now,(int)calc.size()-T.sum(lpos,rpos));
		}/*
		for(set<int>::iterator it=beg.begin();it!=beg.end();++it)
			cout<<*it<<' ';
		cout<<endl;
		for(set<int>::iterator it=end.begin();it!=end.end();++it)
			cout<<*it<<' ';
		cout<<endl;
		cout<<"--------------------------------"<<endl;*/
	}
	long long ans=0;
	for(int i=1;i<=n;++i)
		ans=max(ans,s[get_root(i)]);
	//for(int i=1;i<=n;++i)
	//	cout<<get_root(i)<<endl;
	cout<<ans<<endl;
}
int main()
{
	init();
	work();
	return 0;
}


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cassert>
#include<set>
#include<vector>
using namespace std;
const int N=200020,Inf=1<<30;
class BIT
{
	vector<int> t;
	int presum(int pos)
	{
		int s=0;
		for(int i=pos;i;i-=i&(-i))
			s+=t[i];
		return s;
	}
	public:
	BIT(int n=0): t(n) {}
	void resize(int n)
	{
		t.resize(n+1);
		fill(t.begin(),t.end(),0);
	}
	void add(int pos,int c)
	{
		for(int i=pos;i<=(int)t.size();i+=i&(-i))
			t[i]+=c;
	}
	int sum(int l,int r)
	{
		return presum(r)-presum(l-1);
	}
}T;
struct event
{
	int type,pos,x,y,num;
}e[N+N]={};
bool cmp(const event &e1,const event &e2)
{
	/*
	if(e1.pos<e2.pos)
		return true;
	if(e1.pos>e2.pos)
		return false;
	if(e1.type<e2.type)
		return true;
	if(e1.type>e2.type)
		return false;
	if(e1.y<e2.y)
		return true;
	return false;
	if(e1.y>e2.y)
		return false;  //*/
	return e1.pos<e2.pos || (e1.pos==e2.pos && e1.type<e2.type);
}
int n,m,root[N]={},num[N+N]={};
long long s[N]={};
int get_root(int r)
{
	if(r!=root[r])
		root[r]=get_root(root[r]);
	return root[r];
}
inline void merge(int u,int v,long long delta=0)
{
	//cout<<"u="<<u<<" v="<<v<<endl;
	int ur=get_root(u) , vr=get_root(v);
	if(ur==vr)
		return;
	root[ur]=vr;
	s[vr]+=s[ur]+delta;
	s[ur]=0;
}
void init()
{
	scanf("%d",&n);
	vector<int> v;
	for(int i=1,x1,y1,x2,y2;i<=n;++i)
	{
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		if(x1==x2)
		{
			e[++m]=(event){1,x1,y1,y2,i};
			root[i]=i;
			s[i]=y2-y1;
			v.push_back(y1);
			v.push_back(y2);
		}
		else
		{
			e[++m]=(event){0,x1,y1,1,i};
			e[++m]=(event){2,x2,y1,-1,i};
			root[i]=i;
			s[i]=x2-x1;
			v.push_back(y1);
		}
	}
	sort(v.begin(),v.end());
	v.erase(unique(v.begin(),v.end()) , v.end());
	T.resize(v.size());
	for(int i=1;i<=m;++i)
		if(e[i].type==1)
		{
			e[i].x=lower_bound(v.begin(),v.end(),e[i].x)-v.begin()+1;
			e[i].y=lower_bound(v.begin(),v.end(),e[i].y)-v.begin()+1;
		}
		else
			e[i].x=lower_bound(v.begin(),v.end(),e[i].x)-v.begin()+1;
	sort(e+1,e+m+1,cmp);
	//for(int i=1;i<=m;++i)
	//	cout<<e[i].type<<' '<<e[i].pos<<' '<<e[i].x<<' '<<e[i].y<<' '<<e[i].num<<endl;
	// "No two horizontal segments share common points."
	// "No two vertical segments share common points."
}
void work()
{
	set<int> beg,end,point,calc;
	beg.insert(-Inf);
	end.insert(-Inf);
	beg.insert(Inf);
	end.insert(Inf);
	point.insert(-Inf);
	point.insert(Inf);
	for(int i=1;i<=m;++i)
	{
		if(e[i].type%2==0)
		{
			int pos=e[i].x;
			if(e[i].y==1)
			{
				point.insert(pos);
				num[pos]=e[i].num;
				T.add(pos,1);
				set<int>::iterator end_it=end.lower_bound(pos);
				set<int>::iterator beg_it=--beg.upper_bound(*end_it);
				beg.insert(pos);
				end.insert(pos);
				if(*beg_it<=pos)
				{
					beg.insert(*point.upper_bound(pos));
					end.insert(*(--point.lower_bound(pos)));
				}
			}
			if(e[i].y==-1)
			{
				point.erase(pos);
				num[pos]=0;
				T.add(pos,-1);
				int r=*end.lower_bound(pos);
				int l=*(--beg.upper_bound(pos));
				if(l==pos)
				{
					if(r==pos)
					{
						beg.erase(pos);
						end.erase(pos);
					}
					else
					{
						beg.insert(*point.upper_bound(pos));
						beg.erase(pos);
					}
				}
				else
					if(r==pos)
					{
						end.insert(*(--point.lower_bound(pos)));
						end.erase(pos);
					}
			}
		}
		else
		{
			calc.clear();
			int lpos=e[i].x , rpos=e[i].y;
			//cout<<"lpos="<<lpos<<" rpos="<<rpos<<endl;
			if(point.lower_bound(lpos)==point.upper_bound(rpos))
				continue;
			set<int>::iterator L=end.lower_bound(lpos);
			set<int>::iterator R=end.lower_bound(rpos);
			//cout<<"L="<<*L<<" R="<<*R<<endl;
			if(*(--beg.upper_bound(*R))>rpos)
			{
				if(L==R)
					continue;
				else
					--R;
			}
			int now=num[*R],tmp=0;
			calc.insert(now);
			//cout<<"now="<<now<<endl;
			for(set<int>::iterator it=L;it!=R;it=end.upper_bound(tmp))
			{
				tmp=*it;
				calc.insert(num[tmp]);
				merge(num[tmp],now);
				end.erase(tmp);
				beg.erase(beg.upper_bound(tmp));
			}
			//cout<<"calc.size()="<<calc.size()<<endl;
			merge(e[i].num,now,(int)calc.size()-T.sum(lpos,rpos));
		}
		/*
		for(set<int>::iterator it=beg.begin();it!=beg.end();++it)
			cout<<*it<<' ';
		cout<<endl;
		for(set<int>::iterator it=end.begin();it!=end.end();++it)
			cout<<*it<<' ';
		cout<<endl;
		cout<<"--------------------------------"<<endl;
		//*/
	}
	long long ans=0;
	for(int i=1;i<=n;++i)
		ans=max(ans,s[get_root(i)]);
	//for(int i=1;i<=n;++i)
	//	cout<<get_root(i)<<endl;
	cout<<ans<<endl;
}
int main()
{
	init();
	work();
	return 0;
}


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cassert>
#include<set>
#include<vector>
using namespace std;
const int N=200020,Inf=1<<30;
class BIT
{
	vector<int> t;
	int presum(int pos)
	{
		int s=0;
		for(int i=pos;i;i-=i&(-i))
			s+=t[i];
		return s;
	}
	public:
	BIT(int n=0): t(n) {}
	void resize(int n)
	{
		t.resize(n+1);
		fill(t.begin(),t.end(),0);
	}
	void add(int pos,int c)
	{
		for(int i=pos;i<=(int)t.size();i+=i&(-i))
			t[i]+=c;
	}
	int sum(int l,int r)
	{
		return presum(r)-presum(l-1);
	}
}T;
struct event
{
	int type,pos,x,y,num;
}e[N+N]={};
bool cmp(const event &e1,const event &e2)
{
	if(e1.pos<e2.pos)
		return true;
	if(e1.pos>e2.pos)
		return false;
	if(e1.type<e2.type)
		return true;
	if(e1.type>e2.type)
		return false;
	if(e1.y<e2.y)
		return true;
	return false;
	//if(e1.y>e2.y)
	//	return false;
	//return e1.pos<e2.pos || (e1.pos==e2.pos && e1.type<e2.type);
}
int n,m,root[N]={},num[N+N]={};
long long s[N]={};
int get_root(int r)
{
	if(r!=root[r])
		root[r]=get_root(root[r]);
	return root[r];
}
inline void merge(int u,int v,long long delta=0)
{
	//cout<<"u="<<u<<" v="<<v<<endl;
	int ur=get_root(u) , vr=get_root(v);
	if(ur==vr)
		return;
	root[ur]=vr;
	s[vr]+=s[ur]+delta;
	s[ur]=0;
}
void init()
{
	scanf("%d",&n);
	vector<int> v;
	for(int i=1,x1,y1,x2,y2;i<=n;++i)
	{
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		if(x1==x2)
		{
			e[++m]=(event){1,x1,y1,y2,i};
			root[i]=i;
			s[i]=y2-y1;
			v.push_back(y1);
			v.push_back(y2);
		}
		else
		{
			e[++m]=(event){0,x1,y1,1,i};
			e[++m]=(event){0,x2+1,y1,-1,i};
			root[i]=i;
			s[i]=x2-x1;
			v.push_back(y1);
		}
	}
	sort(v.begin(),v.end());
	v.erase(unique(v.begin(),v.end()) , v.end());
	T.resize(v.size());
	for(int i=1;i<=m;++i)
		if(e[i].type==1)
		{
			e[i].x=lower_bound(v.begin(),v.end(),e[i].x)-v.begin()+1;
			e[i].y=lower_bound(v.begin(),v.end(),e[i].y)-v.begin()+1;
		}
		else
			e[i].x=lower_bound(v.begin(),v.end(),e[i].x)-v.begin()+1;
	sort(e+1,e+m+1,cmp);
	//for(int i=1;i<=m;++i)
	//	cout<<e[i].type<<' '<<e[i].pos<<' '<<e[i].x<<' '<<e[i].y<<' '<<e[i].num<<endl;
	// "No two horizontal segments share common points."
	// "No two vertical segments share common points."
}
void work()
{
	set<int> beg,end,point,calc;
	beg.insert(-Inf);
	end.insert(-Inf);
	beg.insert(Inf);
	end.insert(Inf);
	point.insert(-Inf);
	point.insert(Inf);
	for(int i=1;i<=m;++i)
	{
		if(e[i].type==0)
		{
			int pos=e[i].x;
			if(e[i].y==1)
			{
				point.insert(pos);
				num[pos]=e[i].num;
				T.add(pos,1);
				set<int>::iterator end_it=end.lower_bound(pos);
				set<int>::iterator beg_it=--beg.upper_bound(*end_it);
				beg.insert(pos);
				end.insert(pos);
				if(*beg_it<=pos)
				{
					beg.insert(*point.upper_bound(pos));
					end.insert(*(--point.lower_bound(pos)));
				}
			}
			if(e[i].y==-1)
			{
				point.erase(pos);
				num[pos]=0;
				T.add(pos,-1);
				int r=*end.lower_bound(pos);
				int l=*(--beg.upper_bound(pos));
				if(l==pos)
				{
					if(r==pos)
					{
						beg.erase(pos);
						end.erase(pos);
					}
					else
					{
						beg.insert(*point.upper_bound(pos));
						beg.erase(pos);
					}
				}
				else
					if(r==pos)
					{
						end.insert(*(--point.lower_bound(pos)));
						end.erase(pos);
					}
			}
		}
		else
		{
			calc.clear();
			int lpos=e[i].x , rpos=e[i].y;
			//cout<<"lpos="<<lpos<<" rpos="<<rpos<<endl;
			if(point.lower_bound(lpos)==point.upper_bound(rpos))
				continue;
			set<int>::iterator L=end.lower_bound(lpos);
			set<int>::iterator R=end.lower_bound(rpos);
			//cout<<"L="<<*L<<" R="<<*R<<endl;
			if(*(--beg.upper_bound(*R))>rpos)
			{
				if(L==R)
					continue;
				else
					--R;
			}
			int now=num[*R],tmp=0;
			calc.insert(now);
			//cout<<"now="<<now<<endl;
			for(set<int>::iterator it=L;it!=R;it=end.upper_bound(tmp))
			{
				tmp=*it;
				calc.insert(num[tmp]);
				merge(num[tmp],now);
				end.erase(tmp);
				beg.erase(beg.upper_bound(tmp));
			}
			//cout<<"calc.size()="<<calc.size()<<endl;
			merge(e[i].num,now,(int)calc.size()-T.sum(lpos,rpos));
		}
		/*
		for(set<int>::iterator it=beg.begin();it!=beg.end();++it)
			cout<<*it<<' ';
		cout<<endl;
		for(set<int>::iterator it=end.begin();it!=end.end();++it)
			cout<<*it<<' ';
		cout<<endl;
		cout<<"--------------------------------"<<endl;
		//*/
	}
	long long ans=0;
	for(int i=1;i<=n;++i)
		ans=max(ans,s[get_root(i)]);
	//for(int i=1;i<=n;++i)
	//	cout<<get_root(i)<<endl;
	cout<<ans<<endl;
}
int main()
{
	init();
	work();
	return 0;
}


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cassert>
#include<set>
#include<vector>
using namespace std;
const int N=200020,Inf=1<<30;
class BIT
{
	vector<int> t;
	int presum(int pos)
	{
		int s=0;
		for(int i=pos;i;i-=i&(-i))
			s+=t[i];
		return s;
	}
	public:
	BIT(int n=0): t(n) {}
	void resize(int n)
	{
		t.resize(n+1);
		fill(t.begin(),t.end(),0);
	}
	void add(int pos,int c)
	{
		for(int i=pos;i<=(int)t.size();i+=i&(-i))
			t[i]+=c;
	}
	int sum(int l,int r)
	{
		return presum(r)-presum(l-1);
	}
}T;
struct event
{
	int type,pos,x,y,num;
}e[N+N]={};
bool cmp(const event &e1,const event &e2)
{
	return e1.pos<e2.pos || (e1.pos==e2.pos && e1.type<e2.type);
}
int n,m,root[N]={},num[N+N]={};
long long s[N]={};
int get_root(int r)
{
	if(r!=root[r])
		root[r]=get_root(root[r]);
	return root[r];
}
inline void merge(int u,int v,long long delta=0)
{
	//cout<<"u="<<u<<" v="<<v<<endl;
	int ur=get_root(u) , vr=get_root(v);
	if(ur==vr)
		return;
	root[ur]=vr;
	s[vr]+=s[ur]+delta;
	s[ur]=0;
}
void init()
{
	scanf("%d",&n);
	vector<int> v;
	for(int i=1,x1,y1,x2,y2;i<=n;++i)
	{
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		if(x1==x2)
		{
			e[++m]=(event){1,x1,y1,y2,i};
			root[i]=i;
			s[i]=y2-y1;
			v.push_back(y1);
			v.push_back(y2);
		}
		else
		{
			e[++m]=(event){0,x1,y1,1,i};
			e[++m]=(event){0,x2+1,y1,-1,i};
			root[i]=i;
			s[i]=x2-x1;
			v.push_back(y1);
		}
	}
	sort(v.begin(),v.end());
	v.erase(unique(v.begin(),v.end()) , v.end());
	T.resize(v.size());
	for(int i=1;i<=m;++i)
		if(e[i].type==1)
		{
			e[i].x=lower_bound(v.begin(),v.end(),e[i].x)-v.begin()+1;
			e[i].y=lower_bound(v.begin(),v.end(),e[i].y)-v.begin()+1;
		}
		else
			e[i].x=lower_bound(v.begin(),v.end(),e[i].x)-v.begin()+1;
	sort(e+1,e+m+1,cmp);
	//for(int i=1;i<=m;++i)
	//	cout<<e[i].type<<' '<<e[i].pos<<' '<<e[i].x<<' '<<e[i].y<<' '<<e[i].num<<endl;
	// "No two horizontal segments share common points."
	// "No two vertical segments share common points."
}
void work()
{
	set<int> beg,end,point,calc;
	beg.insert(-Inf);
	end.insert(-Inf);
	beg.insert(Inf);
	end.insert(Inf);
	point.insert(-Inf);
	point.insert(Inf);
	for(int i=1;i<=m;++i)
	{
		if(e[i].type==0)
		{
			int pos=e[i].x;
			if(e[i].y==1)
			{
				point.insert(pos);
				num[pos]=e[i].num;
				T.add(pos,1);
				set<int>::iterator end_it=end.lower_bound(pos);
				set<int>::iterator beg_it=--beg.upper_bound(*end_it);
				beg.insert(pos);
				end.insert(pos);
				if(*beg_it<=pos)
				{
					beg.insert(*point.upper_bound(pos));
					end.insert(*(--point.lower_bound(pos)));
				}
			}
			if(e[i].y==-1)
			{
				point.erase(pos);
				num[pos]=0;
				T.add(pos,-1);
				int r=*end.lower_bound(pos);
				int l=*(--beg.upper_bound(pos));
				if(l==pos)
				{
					if(r==pos)
					{
						beg.erase(pos);
						end.erase(pos);
					}
					else
					{
						beg.insert(*point.upper_bound(pos));
						beg.erase(pos);
					}
				}
				else
					if(r==pos)
					{
						end.insert(*(--point.lower_bound(pos)));
						end.erase(pos);
					}
			}
		}
		else
		{
			calc.clear();
			int lpos=e[i].x , rpos=e[i].y;
			//cout<<"lpos="<<lpos<<" rpos="<<rpos<<endl;
			set<int>::iterator L=end.lower_bound(lpos);
			set<int>::iterator R=end.lower_bound(rpos);
			//cout<<"L="<<*L<<" R="<<*R<<endl;
			if(*R==Inf)
			{
				if(L==R)
					continue;
				else
					--R;
			}
			int now=num[*R],tmp=0;
			calc.insert(now);
			//cout<<"now="<<now<<endl;
			for(set<int>::iterator it=L;it!=R;it=end.upper_bound(tmp))
			{
				tmp=*it;
				calc.insert(num[tmp]);
				merge(num[tmp],now);
				end.erase(tmp);
				beg.erase(beg.upper_bound(tmp));
			}
			//cout<<"calc.size()="<<calc.size()<<endl;
			merge(e[i].num,now,(int)calc.size()-T.sum(lpos,rpos));
		}/*
		for(set<int>::iterator it=beg.begin();it!=beg.end();++it)
			cout<<*it<<' ';
		cout<<endl;
		for(set<int>::iterator it=end.begin();it!=end.end();++it)
			cout<<*it<<' ';
		cout<<endl;
		cout<<"--------------------------------"<<endl;*/
	}
	long long ans=0;
	for(int i=1;i<=n;++i)
		ans=max(ans,s[get_root(i)]);
	cout<<ans<<endl;
}
int main()
{
	init();
	work();
	return 0;
}


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cassert>
#include<set>
#include<vector>
using namespace std;
const int N=200020,Inf=1<<30;
class BIT
{
	vector<int> t;
	int presum(int pos)
	{
		int s=0;
		for(int i=pos;i;i-=i&(-i))
			s+=t[i];
		return s;
	}
	public:
	BIT(int n=0): t(n) {}
	void resize(int n)
	{
		t.resize(n+1);
		fill(t.begin(),t.end(),0);
	}
	void add(int pos,int c)
	{
		for(int i=pos;i<=(int)t.size();i+=i&(-i))
			t[i]+=c;
	}
	int sum(int l,int r)
	{
		return presum(r)-presum(l-1);
	}
}T;
struct event
{
	int type,pos,x,y,num;
}e[N+N]={};
bool cmp(const event &e1,const event &e2)
{
	return e1.pos<e2.pos || (e1.pos==e2.pos && e1.type<e2.type);
}
int n,m,root[N]={},num[N+N]={};
long long s[N]={};
int get_root(int r)
{
	if(r!=root[r])
		root[r]=get_root(root[r]);
	return root[r];
}
inline void merge(int u,int v,long long delta=0)
{
	//cout<<"u="<<u<<" v="<<v<<endl;
	int ur=get_root(u) , vr=get_root(v);
	if(ur==vr)
		return;
	root[ur]=vr;
	s[vr]+=s[ur]+delta;
	s[ur]=0;
}
void init()
{
	scanf("%d",&n);
	vector<int> v;
	for(int i=1,x1,y1,x2,y2;i<=n;++i)
	{
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		if(x1==x2)
		{
			e[++m]=(event){1,x1,y1,y2,i};
			root[i]=i;
			s[i]=y2-y1;
			v.push_back(y1);
			v.push_back(y2);
		}
		else
		{
			e[++m]=(event){0,x1,y1,1,i};
			e[++m]=(event){0,x2+1,y1,-1,i};
			root[i]=i;
			s[i]=x2-x1;
			v.push_back(y1);
		}
	}
	sort(v.begin(),v.end());
	v.erase(unique(v.begin(),v.end()) , v.end());
	T.resize(v.size());
	for(int i=1;i<=m;++i)
		if(e[i].type==1)
		{
			e[i].x=lower_bound(v.begin(),v.end(),e[i].x)-v.begin()+1;
			e[i].y=lower_bound(v.begin(),v.end(),e[i].y)-v.begin()+1;
		}
		else
			e[i].x=lower_bound(v.begin(),v.end(),e[i].x)-v.begin()+1;
	sort(e+1,e+m+1,cmp);
	//for(int i=1;i<=m;++i)
	//	cout<<e[i].type<<' '<<e[i].pos<<' '<<e[i].x<<' '<<e[i].y<<' '<<e[i].num<<endl;
	// "No two horizontal segments share common points."
	// "No two vertical segments share common points."
}
void work()
{
	set<int> beg,end,point,calc;
	beg.insert(-Inf);
	end.insert(-Inf);
	beg.insert(Inf);
	end.insert(Inf);
	point.insert(-Inf);
	point.insert(Inf);
	for(int i=1;i<=m;++i)
	{
		if(e[i].type==0)
		{
			int pos=e[i].x;
			if(e[i].y==1)
			{
				point.insert(pos);
				num[pos]=e[i].num;
				T.add(pos,1);
				set<int>::iterator end_it=end.lower_bound(pos);
				set<int>::iterator beg_it=--beg.upper_bound(*end_it);
				beg.insert(pos);
				end.insert(pos);
				if(*beg_it<=pos)
				{
					beg.insert(*point.upper_bound(pos));
					end.insert(*(--point.lower_bound(pos)));
				}
			}
			if(e[i].y==-1)
			{
				point.erase(pos);
				num[pos]=0;
				T.add(pos,-1);
				int r=*end.lower_bound(pos);
				int l=*(--beg.upper_bound(pos));
				if(l==pos)
				{
					if(r==pos)
					{
						beg.erase(pos);
						end.erase(pos);
					}
					else
					{
						beg.insert(*point.upper_bound(pos));
						beg.erase(pos);
					}
				}
				else
					if(r==pos)
					{
						end.insert(*(--point.lower_bound(pos)));
						end.erase(pos);
					}
			}
		}
		else
		{
			calc.clear();
			int lpos=e[i].x , rpos=e[i].y;
			//cout<<"lpos="<<lpos<<" rpos="<<rpos<<endl;
			if(point.lower_bound(lpos)==point.upper_bound(rpos))
				continue;
			set<int>::iterator L=end.lower_bound(lpos);
			set<int>::iterator R=end.lower_bound(rpos);
			//cout<<"L="<<*L<<" R="<<*R<<endl;
			if(*(--beg.upper_bound(*R))>rpos)
			{
				if(L==R)
					continue;
				else
					--R;
			}
			int now=num[*R],tmp=0;
			calc.insert(now);
			//cout<<"now="<<now<<endl;
			for(set<int>::iterator it=L;it!=R;it=end.upper_bound(tmp))
			{
				tmp=*it;
				calc.insert(num[tmp]);
				merge(num[tmp],now);
				end.erase(tmp);
				beg.erase(beg.upper_bound(tmp));
			}
			//cout<<"calc.size()="<<calc.size()<<endl;
			merge(e[i].num,now,(int)calc.size()-T.sum(lpos,rpos));
		}
		/*
		for(set<int>::iterator it=beg.begin();it!=beg.end();++it)
			cout<<*it<<' ';
		cout<<endl;
		for(set<int>::iterator it=end.begin();it!=end.end();++it)
			cout<<*it<<' ';
		cout<<endl;
		cout<<"--------------------------------"<<endl;
		//*/
	}
	long long ans=0;
	for(int i=1;i<=n;++i)
		ans=max(ans,s[get_root(i)]);
	//for(int i=1;i<=n;++i)
	//	cout<<get_root(i)<<endl;
	cout<<ans<<endl;
}
int main()
{
	init();
	work();
	return 0;
}


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cassert>
#include<set>
#include<vector>
using namespace std;
const int N=200020,Inf=1<<30;
class BIT
{
	vector<int> t;
	int presum(int pos)
	{
		int s=0;
		for(int i=pos;i;i-=i&(-i))
			s+=t[i];
		return s;
	}
	public:
	BIT(int n=0): t(n) {}
	void resize(int n)
	{
		t.resize(n+1);
		fill(t.begin(),t.end(),0);
	}
	void add(int pos,int c)
	{
		for(int i=pos;i<=(int)t.size();i+=i&(-i))
			t[i]+=c;
	}
	int sum(int l,int r)
	{
		return presum(r)-presum(l-1);
	}
}T;
struct event
{
	int type,pos,x,y,num;
}e[N+N]={};
bool cmp(const event &e1,const event &e2)
{
	return e1.pos<e2.pos || (e1.pos==e2.pos && e1.type<e2.type);
}
int n,m,root[N]={},num[N+N]={};
long long s[N]={};
int get_root(int r)
{
	if(r!=root[r])
		root[r]=get_root(root[r]);
	return root[r];
}
inline void merge(int u,int v,long long delta=0)
{
	int ur=get_root(u) , vr=get_root(v);
	if(ur==vr)
		return;
	root[ur]=vr;
	s[vr]+=s[ur]+delta;
	s[ur]=0;
}
void init()
{
	scanf("%d",&n);
	vector<int> v;
	for(int i=1,x1,y1,x2,y2;i<=n;++i)
	{
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		if(x1==x2)
		{
			e[++m]=(event){1,x1,y1,y2,i};
			root[i]=i;
			s[i]=y2-y1;
			v.push_back(y1);
			v.push_back(y2);
		}
		else
		{
			e[++m]=(event){0,x1,y1,0,i};
			e[++m]=(event){2,x2,y1,0,i};
			root[i]=i;
			s[i]=x2-x1;
			v.push_back(y1);
		}
	}
	sort(v.begin(),v.end());
	v.erase(unique(v.begin(),v.end()) , v.end());
	T.resize(v.size());
	for(int i=1;i<=m;++i)
		if(e[i].type==1)
		{
			e[i].x=lower_bound(v.begin(),v.end(),e[i].x)-v.begin()+1;
			e[i].y=lower_bound(v.begin(),v.end(),e[i].y)-v.begin()+1;
		}
		else
			e[i].x=lower_bound(v.begin(),v.end(),e[i].x)-v.begin()+1;
	sort(e+1,e+m+1,cmp);
	// "No two horizontal segments share common points."
	// "No two vertical segments share common points."
}
void work()
{
	set<int> beg,end,point,calc;
	beg.insert(-Inf);
	end.insert(-Inf);
	beg.insert(Inf);
	end.insert(Inf);
	point.insert(-Inf);
	point.insert(Inf);
	for(int i=1;i<=m;++i)
	{
		if(e[i].type==0)
		{
			int pos=e[i].x;
			point.insert(pos);
			num[pos]=e[i].num;
			T.add(pos,1);
			int tmp=*--beg.upper_bound(*end.lower_bound(pos));
			beg.insert(pos);
			end.insert(pos);
			if(tmp<=pos)
			{
				beg.insert(*point.upper_bound(pos));
				end.insert(*(--point.lower_bound(pos)));
			}
		}
		if(e[i].type==2)
		{
			int pos=e[i].x;
			point.erase(pos);
			num[pos]=0;
			T.add(pos,-1);
			int r=*end.lower_bound(pos);
			int l=*(--beg.upper_bound(pos));
			if(l==pos)
			{
				if(r==pos)
				{
					beg.erase(pos);
					end.erase(pos);
				}
				else
				{
					beg.insert(*point.upper_bound(pos));
					beg.erase(pos);
				}
			}
			else
				if(r==pos)
				{
					end.insert(*(--point.lower_bound(pos)));
					end.erase(pos);
				}
		}
		if(e[i].type==1)
		{
			calc.clear();
			int lpos=e[i].x , rpos=e[i].y;
			if(point.lower_bound(lpos)==point.upper_bound(rpos))
				continue;
			set<int>::iterator L=end.lower_bound(lpos);
			set<int>::iterator R=end.lower_bound(rpos);
			if(*(--beg.upper_bound(*R))>rpos)
				--R;
			int r=*R,now=get_root(num[r]),tmp1=0,tmp2=0;
			calc.insert(now);
			for(set<int>::iterator it=L;*it!=r;it=end.upper_bound(tmp1))
			{
				tmp1=*it;
				tmp2=get_root(num[tmp1]); // Notice "get_root()" function.
				calc.insert(tmp2);
				merge(tmp2,now);
				end.erase(tmp1);
				beg.erase(beg.upper_bound(tmp1));
			}
			merge(e[i].num,now,(int)calc.size()-T.sum(lpos,rpos));
		}
	}
	long long ans=0;
	for(int i=1;i<=n;++i)
		ans=max(ans,s[get_root(i)]);
	cout<<ans<<endl;
}
int main()
{
	init();
	work();
	return 0;
}


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cassert>
#include<set>
#include<vector>
using namespace std;
const int N=200020,Inf=1<<30;
class BIT
{
	vector<int> t;
	int presum(int pos)
	{
		int s=0;
		for(int i=pos;i;i-=i&(-i))
			s+=t[i];
		return s;
	}
	public:
	BIT(int n=0): t(n) {}
	void resize(int n)
	{
		t.resize(n+1);
		fill(t.begin(),t.end(),0);
	}
	void add(int pos,int c)
	{
		for(int i=pos;i<=(int)t.size();i+=i&(-i))
			t[i]+=c;
	}
	int sum(int l,int r)
	{
		return presum(r)-presum(l-1);
	}
}T;
struct event
{
	int type,pos,x,y,num;
}e[N+N]={};
bool cmp(const event &e1,const event &e2)
{
	return e1.pos<e2.pos || (e1.pos==e2.pos && e1.type<e2.type);
}
int n,m,root[N]={},num[N+N]={};
long long s[N]={};
int get_root(int r)
{
	if(r!=root[r])
		root[r]=get_root(root[r]);
	return root[r];
}
inline void merge(int u,int v,long long delta=0)
{
	int ur=get_root(u) , vr=get_root(v);
	if(ur==vr)
		return;
	root[ur]=vr;
	s[vr]+=s[ur]+delta;
	s[ur]=0;
}
void init()
{
	//cout<<Inf<<endl;
	scanf("%d",&n);
	vector<int> v;
	for(int i=1,x1,y1,x2,y2;i<=n;++i)
	{
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		if(x1==x2)
		{
			e[++m]=(event){1,x1,y1,y2,i};
			root[i]=i;
			s[i]=y2-y1;
			v.push_back(y1);
			v.push_back(y2);
		}
		else
		{
			e[++m]=(event){0,x1,y1,0,i};
			e[++m]=(event){2,x2,y1,0,i};
			root[i]=i;
			s[i]=x2-x1;
			v.push_back(y1);
		}
	}
	sort(v.begin(),v.end());
	v.erase(unique(v.begin(),v.end()) , v.end());
	T.resize(v.size());
	for(int i=1;i<=m;++i)
		if(e[i].type==1)
		{
			e[i].x=lower_bound(v.begin(),v.end(),e[i].x)-v.begin()+1;
			e[i].y=lower_bound(v.begin(),v.end(),e[i].y)-v.begin()+1;
		}
		else
			e[i].x=lower_bound(v.begin(),v.end(),e[i].x)-v.begin()+1;
	sort(e+1,e+m+1,cmp);
	//for(int i=1;i<=m;++i)
	//	cout<<e[i].type<<' '<<e[i].pos<<' '<<e[i].x<<' '<<e[i].y<<' '<<e[i].num<<endl;
	// "No two horizontal segments share common points."
	// "No two vertical segments share common points."
}
void work()
{
	set<int> beg,end,point,calc;
	beg.insert(-Inf);
	end.insert(-Inf);
	beg.insert(Inf);
	end.insert(Inf);
	point.insert(-Inf);
	point.insert(Inf);
	for(int i=1;i<=m;++i)
	{
		if(e[i].type==0)
		{
			int pos=e[i].x;
			point.insert(pos);
			num[pos]=e[i].num;
			T.add(pos,1);
			int tmp=*--beg.upper_bound(*end.lower_bound(pos));
			beg.insert(pos);
			end.insert(pos);
			if(tmp<=pos)
			{
				beg.insert(*point.upper_bound(pos));
				end.insert(*(--point.lower_bound(pos)));
			}
		}
		if(e[i].type==2)
		{
			int pos=e[i].x;
			point.erase(pos);
			num[pos]=0;
			T.add(pos,-1);
			int r=*end.lower_bound(pos);
			int l=*(--beg.upper_bound(pos));
			if(l==pos)
			{
				if(r==pos)
				{
					beg.erase(pos);
					end.erase(pos);
				}
				else
				{
					beg.insert(*point.upper_bound(pos));
					beg.erase(pos);
				}
			}
			else
				if(r==pos)
				{
					end.insert(*(--point.lower_bound(pos)));
					end.erase(pos);
				}
		}
		if(e[i].type==1)
		{
			calc.clear();
			int lpos=e[i].x , rpos=e[i].y;
			//cout<<"lpos="<<lpos<<" rpos="<<rpos<<endl;
			if(point.lower_bound(lpos)==point.upper_bound(rpos))
				continue;
			set<int>::iterator L=end.lower_bound(lpos);
			set<int>::iterator R=end.lower_bound(rpos);
			//cout<<"L="<<*L<<" R="<<*R<<endl;
			if(*(--beg.upper_bound(*R))>rpos)
				--R;
			int now=num[*R],tmp=0;
			calc.insert(now);
			//cout<<"now="<<now<<endl;
			for(set<int>::iterator it=L;it!=R;it=end.upper_bound(tmp))
			{
				tmp=*it;
				calc.insert(num[tmp]);
				merge(num[tmp],now);
				end.erase(tmp);
				beg.erase(beg.upper_bound(tmp));
			}
			//cout<<"calc.size()="<<calc.size()<<endl;
			merge(e[i].num,now,(int)calc.size()-T.sum(lpos,rpos));
		}
		/*
		for(set<int>::iterator it=beg.begin();it!=beg.end();++it)
			cout<<*it<<' ';
		cout<<endl;
		for(set<int>::iterator it=end.begin();it!=end.end();++it)
			cout<<*it<<' ';
		cout<<endl;
		cout<<"--------------------------------"<<endl;
		//*/
	}
	long long ans=0;
	for(int i=1;i<=n;++i)
		ans=max(ans,s[get_root(i)]);
	//for(int i=1;i<=n;++i)
	//	cout<<get_root(i)<<endl;
	cout<<ans<<endl;
}
int main()
{
	init();
	work();
	return 0;
}


#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 200005
#define M 6000005
#define inf 1000000005
#define ll long long
using namespace std;
int n,f[N],cnt,Rt,nod;ll len[N],Ans;
int ID[M],vis[M],ls[M],rs[M];ll sum[M];
struct T
{
	int x1,y1,y2,id,tp;
}a[N*2];
bool cmp(T a,T b)
{
	return a.x1==b.x1?a.tp<b.tp:a.x1<b.x1;
}
int Get(int x)
{
	return f[x]==x?x:f[x]=Get(f[x]);
}
void add(int &k,int l,int r,int u,int id)
{
	if (!k) k=++nod;
	vis[k]=0;
	if (l==r)
	{
		ID[k]=id;
		sum[k]=1;
		return;
	}
	int mid=l+(r-l)/2;
	if (u<=mid) add(ls[k],l,mid,u,id);
	else add(rs[k],mid+1,r,u,id);
	sum[k]=sum[ls[k]]+sum[rs[k]];
	ID[k]=max(ID[ls[k]],ID[rs[k]]);
}
void del(int &k,int l,int r,int u,int id)
{
	if (!k) k=++nod;
	vis[k]=0;
	if (l==r)
	{
		ID[k]=0;
		sum[k]=0;
		return;
	}
	int mid=l+(r-l)/2;
	if (u<=mid) del(ls[k],l,mid,u,id);
	else del(rs[k],mid+1,r,u,id);
	sum[k]=sum[ls[k]]+sum[rs[k]];
	ID[k]=max(ID[ls[k]],ID[rs[k]]);
}
void work(int k)
{
	if (!k||vis[k]) return;
	vis[k]=1;
	if (ID[ls[k]]&&ID[rs[k]])
		f[Get(ID[ls[k]])]=Get(ID[rs[k]]);
	work(ls[k]);
	work(rs[k]);
}
ll qry(int k,int l,int r,int u,int v,int id)
{
	if ((!k)||(!ID[k]))return 0;
	if (u<=l&&r<=v)
	{
		/**/
		f[Get(ID[k])]=Get(id);
		work(k);
		return sum[k];
	}
	int mid=l+(r-l)/2;ll ans=0;
	if (u<=mid) ans+=qry(ls[k],l,mid,u,v,id);
	if (v>mid) ans+=qry(rs[k],mid+1,r,u,v,id);
	return ans;
}
int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
	{
		int x1,y1,x2,y2;
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		if (x1==x2)
		{
			a[++cnt]=(T){x1,y1,y2,i,2};
		}
		else
		{
			len[i]=x2-x1+1;
			a[++cnt]=(T){x1,y1,0,i,1};
			a[++cnt]=(T){x2,y1,0,i,3};
		}
	}
	for (int i=1;i<=n;i++) f[i]=i;
	sort(a+1,a+cnt+1,cmp);
	for (int i=1;i<=cnt;i++)
	{
		if (a[i].tp==2) len[a[i].id]=a[i].y2-a[i].y1+1-qry(Rt,-inf,inf,a[i].y1,a[i].y2,a[i].id);
		else if (a[i].tp==1) add(Rt,-inf,inf,a[i].y1,a[i].id);
		else del(Rt,-inf,inf,a[i].y1,a[i].id);
	}
	for (int i=1;i<=n;i++)
		if (Get(i)!=i) len[Get(i)]+=len[i];

	for (int i=1;i<=n;i++)
		Ans=max(Ans,len[i]);
	printf("%lld\n",Ans-1);
}


#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 200005
#define M 6000005
#define inf 1000000005
#define ll long long
using namespace std;
ll n,f[N],Ans,cnt,Rt,nod,len[N];
ll ID[M],vis[M],ls[M],rs[M],sum[M];
struct T
{
	ll x1,y1,y2,id,tp;
}a[N*2];
bool cmp(T a,T b)
{
	return a.x1==b.x1?a.tp<b.tp:a.x1<b.x1;
}
ll Get(ll x)
{
	return f[x]==x?x:f[x]=Get(f[x]);
}
void add(ll &k,ll l,ll r,ll u,ll id)
{
	if (!k) k=++nod;
	vis[k]=0;
	if (l==r)
	{
		ID[k]=id;
		sum[k]=1;
		return;
	}
	ll mid=(l+r)/2;
	if (u<=mid) add(ls[k],l,mid,u,id);
	else add(rs[k],mid+1,r,u,id);
	sum[k]=sum[ls[k]]+sum[rs[k]];
	ID[k]=max(ID[ls[k]],ID[rs[k]]);
}
void del(ll &k,ll l,ll r,ll u,ll id)
{
	if (!k) k=++nod;
	vis[k]=0;
	if (l==r)
	{
		ID[k]=0;
		sum[k]=0;
		return;
	}
	ll mid=(l+r)/2;
	if (u<=mid) del(ls[k],l,mid,u,id);
	else del(rs[k],mid+1,r,u,id);
	sum[k]=sum[ls[k]]+sum[rs[k]];
	ID[k]=max(ID[ls[k]],ID[rs[k]]);
}
void work(ll k)
{
	if (!k||vis[k]) return;
	vis[k]=1;
	if (ID[ls[k]]&&ID[rs[k]])
		f[Get(ID[ls[k]])]=Get(ID[rs[k]]);
	work(ls[k]);
	work(rs[k]);
}
ll qry(ll k,ll l,ll r,ll u,ll v,ll id)
{
	if ((!k)||(!ID[k]))return 0;
	if (u<=l&&r<=v)
	{
		/**/
		f[Get(ID[k])]=Get(id);
		work(k);
		return sum[k];
	}
	ll mid=(l+r)/2,ans=0;
	if (u<=mid) ans+=qry(ls[k],l,mid,u,v,id);
	if (v>mid) ans+=qry(rs[k],mid+1,r,u,v,id);
	return ans;
}
int main()
{
	scanf("%lld",&n);
	for (ll i=1;i<=n;i++)
	{
		ll x1,y1,x2,y2;
		scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
		if (x1==x2)
		{
			a[++cnt]=(T){x1,y1,y2,i,2};
		}
		else
		{
			len[i]=x2-x1+1;
			a[++cnt]=(T){x1,y1,0,i,1};
			a[++cnt]=(T){x2,y1,0,i,3};
		}
	}
	for (ll i=1;i<=n;i++) f[i]=i;
	sort(a+1,a+cnt+1,cmp);
	for (ll i=1;i<=cnt;i++)
	{
		//cout<<a[i].x1<<' '<<a[i].y1<<' '<<a[i].y2<<' '<<a[i].id<<endl;
		if (a[i].tp==2) len[a[i].id]=a[i].y2-a[i].y1+1-qry(Rt,-inf,inf,a[i].y1,a[i].y2,a[i].id);
		else if (a[i].tp==1) add(Rt,-inf,inf,a[i].y1,a[i].id);
		else del(Rt,-inf,inf,a[i].y1,a[i].id);
	}
	for (ll i=1;i<=n;i++)
	{
		//printf("%lld\n",Get(i));
		if (Get(i)!=i) len[Get(i)]+=len[i];
	}
	for (ll i=1;i<=n;i++)
		Ans=max(Ans,len[i]);
	printf("%lld\n",Ans-1);
}


#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 200005
#define M 6000005
#define inf 100000005
#define ll long long
using namespace std;
int n,f[N],cnt,Rt,nod;ll len[N],Ans;
int ID[M],vis[M],ls[M],rs[M];ll sum[M];
struct T
{
	int x1,y1,y2,id,tp;
}a[N*2];
bool cmp(T a,T b)
{
	return a.x1==b.x1?a.tp<b.tp:a.x1<b.x1;
}
int Get(int x)
{
	return f[x]==x?x:f[x]=Get(f[x]);
}
void add(int &k,int l,int r,int u,int id)
{
	if (!k) k=++nod;
	vis[k]=0;
	if (l==r)
	{
		ID[k]=id;
		sum[k]=1;
		return;
	}
	int mid=(l+r)/2;
	if (u<=mid) add(ls[k],l,mid,u,id);
	else add(rs[k],mid+1,r,u,id);
	sum[k]=sum[ls[k]]+sum[rs[k]];
	ID[k]=max(ID[ls[k]],ID[rs[k]]);
}
void del(int &k,int l,int r,int u,int id)
{
	if (!k) k=++nod;
	vis[k]=0;
	if (l==r)
	{
		ID[k]=0;
		sum[k]=0;
		return;
	}
	int mid=(l+r)/2;
	if (u<=mid) del(ls[k],l,mid,u,id);
	else del(rs[k],mid+1,r,u,id);
	sum[k]=sum[ls[k]]+sum[rs[k]];
	ID[k]=max(ID[ls[k]],ID[rs[k]]);
}
void work(int k)
{
	if (!k||vis[k]) return;
	vis[k]=1;
	if (ID[ls[k]]&&ID[rs[k]])
		f[Get(ID[ls[k]])]=Get(ID[rs[k]]);
	work(ls[k]);
	work(rs[k]);
}
ll qry(int k,int l,int r,int u,int v,int id)
{
	if ((!k)||(!ID[k]))return 0;
	if (u<=l&&r<=v)
	{
		/**/
		f[Get(ID[k])]=Get(id);
		work(k);
		return sum[k];
	}
	int mid=(l+r)/2;ll ans=0;
	if (u<=mid) ans+=qry(ls[k],l,mid,u,v,id);
	if (v>mid) ans+=qry(rs[k],mid+1,r,u,v,id);
	return ans;
}
int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
	{
		int x1,y1,x2,y2;
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		if (x1==x2)
		{
			a[++cnt]=(T){x1,y1,y2,i,2};
		}
		else
		{
			len[i]=x2-x1+1;
			a[++cnt]=(T){x1,y1,0,i,1};
			a[++cnt]=(T){x2,y1,0,i,3};
		}
	}
	for (int i=1;i<=n;i++) f[i]=i;
	sort(a+1,a+cnt+1,cmp);
	//puts("om");
	for (int i=1;i<=cnt;i++)
	{
		//cout<<a[i].x1<<' '<<a[i].y1<<' '<<a[i].y2<<' '<<a[i].id<<endl;
		if (a[i].tp==2) len[a[i].id]=a[i].y2-a[i].y1+1-qry(Rt,-inf,inf,a[i].y1,a[i].y2,a[i].id);
		else if (a[i].tp==1) add(Rt,-inf,inf,a[i].y1,a[i].id);
		else del(Rt,-inf,inf,a[i].y1,a[i].id);
	}
	for (int i=1;i<=n;i++)
		if (Get(i)!=i) len[Get(i)]+=len[i];

	for (int i=1;i<=n;i++)
		Ans=max(Ans,len[i]);
	printf("%lld\n",Ans-1);
}


#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 200005
#define M 6000005
#define inf 10000005
#define ll long long
using namespace std;
int n,f[N],Ans,cnt,Rt,nod,len[N];
int ID[M],vis[M],ls[M],rs[M],sum[M];
struct T
{
	int x1,y1,y2,id,tp;
}a[N*2];
bool cmp(T a,T b)
{
	return a.x1==b.x1?a.tp<b.tp:a.x1<b.x1;
}
int Get(int x)
{
	return f[x]==x?x:f[x]=Get(f[x]);
}
void add(int &k,int l,int r,int u,int id)
{
	if (!k) k=++nod;
	vis[k]=0;
	if (l==r)
	{
		ID[k]=id;
		sum[k]=1;
		return;
	}
	int mid=(l+r)/2;
	if (u<=mid) add(ls[k],l,mid,u,id);
	else add(rs[k],mid+1,r,u,id);
	sum[k]=sum[ls[k]]+sum[rs[k]];
	ID[k]=max(ID[ls[k]],ID[rs[k]]);
}
void del(int &k,int l,int r,int u,int id)
{
	if (!k) k=++nod;
	vis[k]=0;
	if (l==r)
	{
		ID[k]=0;
		sum[k]=0;
		return;
	}
	int mid=(l+r)/2;
	if (u<=mid) del(ls[k],l,mid,u,id);
	else del(rs[k],mid+1,r,u,id);
	sum[k]=sum[ls[k]]+sum[rs[k]];
	ID[k]=max(ID[ls[k]],ID[rs[k]]);
}
void work(int k)
{
	if (!k||vis[k]) return;
	vis[k]=1;
	if (ID[ls[k]]&&ID[rs[k]])
		f[Get(ID[ls[k]])]=Get(ID[rs[k]]);
	work(ls[k]);
	work(rs[k]);
}
int qry(int k,int l,int r,int u,int v,int id)
{
	if ((!k)||(!ID[k]))return 0;
	if (u<=l&&r<=v)
	{
		/**/
		f[Get(ID[k])]=Get(id);
		work(k);
		return sum[k];
	}
	int mid=(l+r)/2,ans=0;
	if (u<=mid) ans+=qry(ls[k],l,mid,u,v,id);
	if (v>mid) ans+=qry(rs[k],mid+1,r,u,v,id);
	return ans;
}
int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
	{
		int x1,y1,x2,y2;
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		if (x1==x2)
		{
			a[++cnt]=(T){x1,y1,y2,i,2};
		}
		else
		{
			len[i]=x2-x1+1;
			a[++cnt]=(T){x1,y1,0,i,1};
			a[++cnt]=(T){x2,y1,0,i,3};
		}
	}
	for (int i=1;i<=n;i++) f[i]=i;
	sort(a+1,a+cnt+1,cmp);
	//puts("om");
	for (int i=1;i<=cnt;i++)
	{
		//cout<<a[i].x1<<' '<<a[i].y1<<' '<<a[i].y2<<' '<<a[i].id<<endl;
		if (a[i].tp==2) len[a[i].id]=a[i].y2-a[i].y1+1-qry(Rt,-inf,inf,a[i].y1,a[i].y2,a[i].id);
		else if (a[i].tp==1) add(Rt,-inf,inf,a[i].y1,a[i].id);
		else del(Rt,-inf,inf,a[i].y1,a[i].id);
	}
	for (int i=1;i<=n;i++)
		if (Get(i)!=i) len[Get(i)]+=len[i];

	for (int i=1;i<=n;i++)
		Ans=max(Ans,len[i]);
	printf("%d\n",Ans-1);
}


#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 200005
#define M 6000005
#define inf 100000005
#define ll long long
using namespace std;
int n,f[N],cnt,Rt,nod;ll len[N],Ans;
int ID[M],vis[M],ls[M],rs[M];ll sum[M];
struct T
{
	int x1,y1,y2,id,tp;
}a[N*2];
bool cmp(T a,T b)
{
	return a.x1==b.x1?a.tp<b.tp:a.x1<b.x1;
}
int Get(int x)
{
	return f[x]==x?x:f[x]=Get(f[x]);
}
void add(int &k,int l,int r,int u,int id)
{
	if (!k) k=++nod;
	vis[k]=0;
	if (l==r)
	{
		ID[k]=id;
		sum[k]=1;
		return;
	}
	int mid=l+(r-l)/2;
	if (u<=mid) add(ls[k],l,mid,u,id);
	else add(rs[k],mid+1,r,u,id);
	sum[k]=sum[ls[k]]+sum[rs[k]];
	ID[k]=max(ID[ls[k]],ID[rs[k]]);
}
void del(int &k,int l,int r,int u,int id)
{
	if (!k) k=++nod;
	vis[k]=0;
	if (l==r)
	{
		ID[k]=0;
		sum[k]=0;
		return;
	}
	int mid=l+(r-l)/2;
	if (u<=mid) del(ls[k],l,mid,u,id);
	else del(rs[k],mid+1,r,u,id);
	sum[k]=sum[ls[k]]+sum[rs[k]];
	ID[k]=max(ID[ls[k]],ID[rs[k]]);
}
void work(int k)
{
	if (!k||vis[k]) return;
	vis[k]=1;
	if (ID[ls[k]]&&ID[rs[k]])
		f[Get(ID[ls[k]])]=Get(ID[rs[k]]);
	work(ls[k]);
	work(rs[k]);
}
ll qry(int k,int l,int r,int u,int v,int id)
{
	if ((!k)||(!ID[k]))return 0;
	if (u<=l&&r<=v)
	{
		/**/
		f[Get(ID[k])]=Get(id);
		work(k);
		return sum[k];
	}
	int mid=l+(r-l)/2;ll ans=0;
	if (u<=mid) ans+=qry(ls[k],l,mid,u,v,id);
	if (v>mid) ans+=qry(rs[k],mid+1,r,u,v,id);
	return ans;
}
int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
	{
		int x1,y1,x2,y2;
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		if (x1==x2)
		{
			a[++cnt]=(T){x1,y1,y2,i,2};
		}
		else
		{
			len[i]=x2-x1+1;
			a[++cnt]=(T){x1,y1,0,i,1};
			a[++cnt]=(T){x2,y1,0,i,3};
		}
	}
	for (int i=1;i<=n;i++) f[i]=i;
	sort(a+1,a+cnt+1,cmp);
	for (int i=1;i<=cnt;i++)
	{
		if (a[i].tp==2) len[a[i].id]=a[i].y2-a[i].y1+1-qry(Rt,-inf,inf,a[i].y1,a[i].y2,a[i].id);
		else if (a[i].tp==1) add(Rt,-inf,inf,a[i].y1,a[i].id);
		else del(Rt,-inf,inf,a[i].y1,a[i].id);
	}
	for (int i=1;i<=n;i++)
		if (Get(i)!=i) len[Get(i)]+=len[i];

	for (int i=1;i<=n;i++)
		Ans=max(Ans,len[i]);
	printf("%lld\n",Ans-1);
}


#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 200005
#define M 8000005
#define inf 1000000005
#define ll long long
using namespace std;
ll n,f[N],Ans,cnt,Rt,nod,len[N];
ll ID[M],vis[M],ls[M],rs[M],sum[M];
struct T
{
	ll x1,y1,y2,id,tp;
}a[N*2];
bool cmp(T a,T b)
{
	return a.x1==b.x1?a.tp<b.tp:a.x1<b.x1;
}
ll Get(ll x)
{
	return f[x]==x?x:f[x]=Get(f[x]);
}
void add(ll &k,ll l,ll r,ll u,ll id)
{
	if (!k) k=++nod;
	vis[k]=0;
	if (l==r)
	{
		ID[k]=id;
		sum[k]=1;
		return;
	}
	ll mid=(l+r)/2;
	if (u<=mid) add(ls[k],l,mid,u,id);
	else add(rs[k],mid+1,r,u,id);
	sum[k]=sum[ls[k]]+sum[rs[k]];
	ID[k]=max(ID[ls[k]],ID[rs[k]]);
}
void del(ll &k,ll l,ll r,ll u,ll id)
{
	if (!k) k=++nod;
	vis[k]=0;
	if (l==r)
	{
		ID[k]=0;
		sum[k]=0;
		return;
	}
	ll mid=(l+r)/2;
	if (u<=mid) del(ls[k],l,mid,u,id);
	else del(rs[k],mid+1,r,u,id);
	sum[k]=sum[ls[k]]+sum[rs[k]];
	ID[k]=max(ID[ls[k]],ID[rs[k]]);
}
void work(ll k)
{
	if (!k||vis[k]) return;
	vis[k]=1;
	if (ID[ls[k]]&&ID[rs[k]])
		f[Get(ID[ls[k]])]=Get(ID[rs[k]]);
	work(ls[k]);
	work(rs[k]);
}
ll qry(ll k,ll l,ll r,ll u,ll v,ll id)
{
	if ((!k)||(!ID[k]))return 0;
	if (u<=l&&r<=v)
	{
		/**/
		f[Get(ID[k])]=Get(id);
		work(k);
		return sum[k];
	}
	ll mid=(l+r)/2,ans=0;
	if (u<=mid) ans+=qry(ls[k],l,mid,u,v,id);
	if (v>mid) ans+=qry(rs[k],mid+1,r,u,v,id);
	return ans;
}
int main()
{
	scanf("%lld",&n);
	for (ll i=1;i<=n;i++)
	{
		ll x1,y1,x2,y2;
		scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
		if (x1==x2)
		{
			a[++cnt]=(T){x1,y1,y2,i,2};
		}
		else
		{
			len[i]=x2-x1+1;
			a[++cnt]=(T){x1,y1,0,i,1};
			a[++cnt]=(T){x2,y1,0,i,3};
		}
	}
	for (ll i=1;i<=n;i++) f[i]=i;
	sort(a+1,a+cnt+1,cmp);
	for (ll i=1;i<=cnt;i++)
	{
		//cout<<a[i].x1<<' '<<a[i].y1<<' '<<a[i].y2<<' '<<a[i].id<<endl;
		if (a[i].tp==2) len[a[i].id]=a[i].y2-a[i].y1+1-qry(Rt,-inf,inf,a[i].y1,a[i].y2,a[i].id);
		else if (a[i].tp==1) add(Rt,-inf,inf,a[i].y1,a[i].id);
		else del(Rt,-inf,inf,a[i].y1,a[i].id);
	}
	for (ll i=1;i<=n;i++)
	{
		//printf("%lld\n",Get(i));
		if (Get(i)!=i) len[Get(i)]+=len[i];
	}
	for (ll i=1;i<=n;i++)
		Ans=max(Ans,len[i]);
	printf("%lld\n",Ans-1);
}