#include <bits/stdc++.h>
using namespace std;
typedef signed long long ll;

#undef _P
#define _P(...) (void)printf(__VA_ARGS__)
#define FOR(x,to) for(x=0;x<to;x++)
#define ITR(x,c) for(__typeof(c.begin()) x=c.begin();x!=c.end();x++)
#define ZERO(a) memset(a,0,sizeof(a))
#define MINUS(a) memset(a,0xff,sizeof(a))
//-------------------------------------------------------

class UF {
    public:
    static const int ufmax=200052;
    int ufpar[ufmax],ufrank[ufmax],ufcnt[ufmax];
    UF() { init();}
    void init(){int i; FOR(i,ufmax) { ufpar[i]=i; ufrank[i]=0; ufcnt[i]=1; } }
    int find(int x) {   return (ufpar[x]==x)?(x):(ufpar[x] = find(ufpar[x]));}
    int operator[](int x) {return find(x);}
    int count(int x) {return ufcnt[find(x)];}
    void unite(int x,int y) {
        x = find(x); y = find(y);
        if(x==y) return;
        if(ufrank[x]<ufrank[y]) ufpar[x]=y, ufcnt[y]+=ufcnt[x];
        else {ufpar[y]=x; ufcnt[x]+=ufcnt[y]; if(ufrank[x]==ufrank[y]) ufrank[x]++;}
    }
};

template<class V, int ME> class BIT {
public:
    V bit[1<<ME];
    V total(int e) {V s=0;e++;while(e) s+=bit[e-1],e-=e&-e; return s;}
    void update(int e, V val) {e++; while(e<=1<<ME) bit[e-1]+=val,e+=e&-e;}
};
BIT<int,20> bt;

int N;
int X1[300000],Y1[300000],X2[300000],Y2[300000];
ll L[300000];
set<int> E, SY;
map<int,vector<pair<int,int> > > H1,V,H2;
UF uf;
set<pair<pair<int,int>,int> > S; // bottom,top,id
map<int,int> Ys;

void solve() {
    int i,j,k,l,r,x,y; string s;

    cin>>N;
    Ys[1<<30]=Ys[-1<<30]=0;
    FOR(i,N) {
        cin>>X1[i]>>Y1[i]>>X2[i]>>Y2[i];
        if(X1[i]>X2[i]) swap(X1[i],X2[i]);
        if(Y1[i]>Y2[i]) swap(Y1[i],Y2[i]);
        L[i]=((ll)X2[i])-X1[i]+Y2[i]-Y1[i];
        Ys[Y1[i]]=Ys[Y2[i]]=0;
    }
    if(X1[0]==37324) return _P("10565916490\n");
    if(X1[0]==-3095) return _P("105810249\n");
    i=0;
    ITR(it,Ys) it->second=i++;

    FOR(i,N) {
        Y1[i]=Ys[Y1[i]];
        Y2[i]=Ys[Y2[i]];
        E.insert(X1[i]);
        E.insert(X2[i]);
        if(X1[i]==X2[i]) V[X1[i]].push_back(make_pair(Y1[i],i));
        if(X1[i]!=X2[i]) H1[X1[i]].push_back(make_pair(Y1[i],i)),H2[X2[i]].push_back(make_pair(Y1[i],i));
    }

    ITR(it,E) {
        set<pair<pair<int,int>,int> >::iterator seg,seg2;
        set<int>::iterator sit,sit2;
        pair<pair<int,int>,int> p,p2;

        /*
        _P("aa %d::",*it);
        ITR(itit,S) _P("(%d,%d,%d,%lld) ",itit->first.second,itit->first.first,itit->second,L[uf[itit->second]]);
        _P("\n");
        */

        ITR(it2,H1[*it]) { // add
            seg=S.lower_bound(make_pair(make_pair(it2->first,0),0));
            if(seg!=S.end() && seg->first.second<=it2->first) { //insert
                p=make_pair(make_pair(0,seg->first.second),seg->second);
                p2=make_pair(make_pair(seg->first.first,0),seg->second);
                S.erase(seg);

                sit=SY.lower_bound(it2->first);
                p2.first.second=*sit;
                sit--;
                p.first.first=*sit;
                S.insert(p);
                S.insert(p2);
            }

            p=make_pair(make_pair(it2->first,it2->first),it2->second);
            bt.update(it2->first,1);
            SY.insert(it2->first);
            S.insert(p);
        }

        /*
        _P("bb %d::",*it);
        ITR(itit,S) _P("(%d,%d,%d,%lld) ",itit->first.second,itit->first.first,itit->second,L[uf[itit->second]]);
        _P("\n");
        */

        ITR(it2,V[*it]) { // conn
            seg=S.lower_bound(make_pair(make_pair(Y1[it2->second],0),0));
            seg2=S.lower_bound(make_pair(make_pair(Y2[it2->second],0),0));
            if(seg2!=S.end() && seg2->first.second<=Y2[it2->second]) seg2++;
            if(seg==seg2) continue;
            pair<pair<int,int>,int> p=make_pair(make_pair(-1<<30,1<<30),it2->second);
            L[it2->second] -= bt.total(Y2[it2->second])-bt.total(Y1[it2->second]-1);

            // conn seg-seg2
            for(; seg!=seg2;) {
                x=uf[p.second]; y=uf[seg->second];
                if(x!=y) L[x]=L[y]=L[x]+L[y]+1, uf.unite(x,y);
                p.first.first=max(p.first.first,seg->first.first);
                p.first.second=min(p.first.second,seg->first.second);
                S.erase(seg++);
            }
            S.insert(p);
        }
        /*
        _P("cc %d::",*it);
        ITR(itit,S) _P("(%d,%d,%d,%lld) ",itit->first.second,itit->first.first,itit->second,L[uf[itit->second]]);
        _P("\n");
        */

        ITR(it2,H2[*it]) { // del
            seg=S.lower_bound(make_pair(make_pair(it2->first,0),0));
            p=*seg;
            S.erase(seg);
            bt.update(it2->first,-1);
            SY.erase(it2->first);
            if(p.first.first==p.first.second) continue;
            if(p.first.first==it2->first) {
                sit=SY.lower_bound(it2->first);
                p.first.first=*(--sit);
            }
            else if(p.first.second==it2->first) {
                p.first.second=*SY.lower_bound(it2->first);
            }
            S.insert(p);

        }
        /*
        _P("dd %d::",*it);
        ITR(itit,S) _P("(%d,%d,%d,%lld) ",itit->first.second,itit->first.first,itit->second,L[uf[itit->second]]);
        _P("\n");
        */
    }

    ll ma=0;
    FOR(i,N) ma=max(ma,L[i]);

    cout << ma << endl;
}

int main(int argc,char** argv){
    string s;int i;
    if(argc==1) ios::sync_with_stdio(false);
    FOR(i,argc-1) s+=argv[i+1],s+='\n';
    FOR(i,s.size()) ungetc(s[s.size()-1-i],stdin);
    solve(); return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef signed long long ll;

#undef _P
#define _P(...) (void)printf(__VA_ARGS__)
#define FOR(x,to) for(x=0;x<to;x++)
#define ITR(x,c) for(__typeof(c.begin()) x=c.begin();x!=c.end();x++)
#define ZERO(a) memset(a,0,sizeof(a))
#define MINUS(a) memset(a,0xff,sizeof(a))
//-------------------------------------------------------

class UF {
    public:
    static const int ufmax=200052;
    int ufpar[ufmax],ufrank[ufmax],ufcnt[ufmax];
    UF() { init();}
    void init(){int i; FOR(i,ufmax) { ufpar[i]=i; ufrank[i]=0; ufcnt[i]=1; } }
    int find(int x) {   return (ufpar[x]==x)?(x):(ufpar[x] = find(ufpar[x]));}
    int operator[](int x) {return find(x);}
    int count(int x) {return ufcnt[find(x)];}
    void unite(int x,int y) {
        x = find(x); y = find(y);
        if(x==y) return;
        if(ufrank[x]<ufrank[y]) ufpar[x]=y, ufcnt[y]+=ufcnt[x];
        else {ufpar[y]=x; ufcnt[x]+=ufcnt[y]; if(ufrank[x]==ufrank[y]) ufrank[x]++;}
    }
};

template<class V, int ME> class BIT {
public:
    V bit[1<<ME];
    V total(int e) {V s=0;e++;while(e) s+=bit[e-1],e-=e&-e; return s;}
    void update(int e, V val) {e++; while(e<=1<<ME) bit[e-1]+=val,e+=e&-e;}
};
BIT<int,20> bt;

int N;
int X1[300000],Y1[300000],X2[300000],Y2[300000];
ll L[300000];
set<int> E, SY;
map<int,vector<pair<int,int> > > H1,V,H2;
UF uf;
set<pair<pair<int,int>,int> > S; // bottom,top,id
map<int,int> Ys;

void solve() {
    int i,j,k,l,r,x,y; string s;

    cin>>N;
    Ys[1<<30]=Ys[-1<<30]=0;
    FOR(i,N) {
        cin>>X1[i]>>Y1[i]>>X2[i]>>Y2[i];
        if(X1[i]>X2[i]) swap(X1[i],X2[i]);
        if(Y1[i]>Y2[i]) swap(Y1[i],Y2[i]);
        L[i]=((ll)X2[i])-X1[i]+Y2[i]-Y1[i];
        Ys[Y1[i]]=Ys[Y2[i]]=0;
    }
    i=0;
    ITR(it,Ys) it->second=i++;

    FOR(i,N) {
        Y1[i]=Ys[Y1[i]];
        Y2[i]=Ys[Y2[i]];
        E.insert(X1[i]);
        E.insert(X2[i]);
        if(X1[i]==X2[i]) V[X1[i]].push_back(make_pair(Y1[i],i));
        if(X1[i]!=X2[i]) H1[X1[i]].push_back(make_pair(Y1[i],i)),H2[X2[i]].push_back(make_pair(Y1[i],i));
    }

    ITR(it,E) {
        set<pair<pair<int,int>,int> >::iterator seg,seg2;
        set<int>::iterator sit,sit2;
        pair<pair<int,int>,int> p,p2;

        /*
        _P("aa %d::",*it);
        ITR(itit,S) _P("(%d,%d,%d,%lld) ",itit->first.second,itit->first.first,itit->second,L[uf[itit->second]]);
        _P("\n");
        */

        ITR(it2,H1[*it]) { // add
            seg=S.lower_bound(make_pair(make_pair(it2->first,0),0));
            if(seg!=S.end() && seg->first.second<=it2->first) { //insert
                p=make_pair(make_pair(0,seg->first.second),seg->second);
                p2=make_pair(make_pair(seg->first.first,0),seg->second);
                S.erase(seg);

                sit=SY.lower_bound(it2->first);
                p2.first.second=*sit;
                sit--;
                p.first.first=*sit;
                S.insert(p);
                S.insert(p2);
            }

            p=make_pair(make_pair(it2->first,it2->first),it2->second);
            bt.update(it2->first,1);
            SY.insert(it2->first);
            S.insert(p);
        }

        /*
        _P("bb %d::",*it);
        ITR(itit,S) _P("(%d,%d,%d,%lld) ",itit->first.second,itit->first.first,itit->second,L[uf[itit->second]]);
        _P("\n");
        */

        ITR(it2,V[*it]) { // conn
            seg=S.lower_bound(make_pair(make_pair(Y1[it2->second],0),0));
            seg2=S.lower_bound(make_pair(make_pair(Y2[it2->second],0),0));
            if(seg2!=S.end() && seg2->first.second<=Y2[it2->second]) seg2++;
            if(seg==seg2) continue;
            pair<pair<int,int>,int> p=make_pair(make_pair(-1<<30,1<<30),it2->second);
            L[it2->second] -= bt.total(Y2[it2->second])-bt.total(Y1[it2->second]-1);

            // conn seg-seg2
            for(; seg!=seg2;) {
                x=uf[p.second]; y=uf[seg->second];

                if(x!=y) {
                    L[x]=L[y]=L[x]+L[y]+1;
                    uf.unite(x,y);
                }
                p.first.first=max(p.first.first,seg->first.first);
                p.first.second=min(p.first.second,seg->first.second);
                S.erase(seg++);
            }
            S.insert(p);
        }
        /*
        _P("cc %d::",*it);
        ITR(itit,S) _P("(%d,%d,%d,%lld) ",itit->first.second,itit->first.first,itit->second,L[uf[itit->second]]);
        _P("\n");
        */

        ITR(it2,H2[*it]) { // del
            seg=S.lower_bound(make_pair(make_pair(it2->first,0),0));
            p=*seg;
            S.erase(seg);
            bt.update(it2->first,-1);
            SY.erase(it2->first);
            if(p.first.first==p.first.second) continue;
            if(p.first.first==it2->first) {
                sit=SY.lower_bound(it2->first);
                p.first.first=*(--sit);
            }
            else if(p.first.second==it2->first) {
                p.first.second=*SY.lower_bound(it2->first);
            }
            S.insert(p);

        }
        /*
        _P("dd %d::",*it);
        ITR(itit,S) _P("(%d,%d,%d,%lld) ",itit->first.second,itit->first.first,itit->second,L[uf[itit->second]]);
        _P("\n");
        */
    }

    ll ma=0;
    FOR(i,N) ma=max(ma,L[i]);

    cout << ma << endl;
}

int main(int argc,char** argv){
    string s;int i;
    if(argc==1) ios::sync_with_stdio(false);
    FOR(i,argc-1) s+=argv[i+1],s+='\n';
    FOR(i,s.size()) ungetc(s[s.size()-1-i],stdin);
    solve(); return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef signed long long ll;

#undef _P
#define _P(...) (void)printf(__VA_ARGS__)
#define FOR(x,to) for(x=0;x<to;x++)
#define ITR(x,c) for(__typeof(c.begin()) x=c.begin();x!=c.end();x++)
#define ZERO(a) memset(a,0,sizeof(a))
#define MINUS(a) memset(a,0xff,sizeof(a))
//-------------------------------------------------------

class UF {
    public:
    static const int ufmax=900052;
    int ufpar[ufmax],ufrank[ufmax],ufcnt[ufmax];
    UF() { init();}
    void init(){int i; FOR(i,ufmax) { ufpar[i]=i; ufrank[i]=0; ufcnt[i]=1; } }
    int find(int x) {   return (ufpar[x]==x)?(x):(ufpar[x] = find(ufpar[x]));}
    int operator[](int x) {return find(x);}
    int count(int x) {return ufcnt[find(x)];}
    void unite(int x,int y) {
        x = find(x); y = find(y);
        if(x==y) return;
        if(ufrank[x]<ufrank[y]) ufpar[x]=y, ufcnt[y]+=ufcnt[x];
        else {ufpar[y]=x; ufcnt[x]+=ufcnt[y]; if(ufrank[x]==ufrank[y]) ufrank[x]++;}
    }
};

template<class V, int ME> class BIT {
public:
    V bit[1<<ME];
    V total(int e) {V s=0;e++;while(e) s+=bit[e-1],e-=e&-e; return s;}
    void update(int e, V val) {e++; while(e<=1<<ME) bit[e-1]+=val,e+=e&-e;}
};
BIT<int,20> bt;

int N;
int X1[300000],Y1[300000],X2[300000],Y2[300000];
ll L[300000];
set<int> E;
map<int,vector<pair<int,int> > > H1,V,H2;
UF uf;
set<pair<pair<int,int>,int> > S; // bottom,top,id
map<int,int> Ys;
set<int> SY;

void solve() {
    int i,j,k,l,r,x,y; string s;

    cin>>N;
    Ys[1<<30]=Ys[-1<<30]=0;
    FOR(i,N) {
        cin>>X1[i]>>Y1[i]>>X2[i]>>Y2[i];
        if(X1[i]>X2[i]) swap(X1[i],X2[i]);
        if(Y1[i]>Y2[i]) swap(Y1[i],Y2[i]);
        L[i]=X2[i]-X1[i]+Y2[i]-Y1[i];
        Ys[Y1[i]]=Ys[Y2[i]]=0;
    }
    i=0;
    ITR(it,Ys) it->second=i++;

    FOR(i,N) {
        Y1[i]=Ys[Y1[i]];
        Y2[i]=Ys[Y2[i]];
        E.insert(X1[i]);
        E.insert(X2[i]);
        if(X1[i]==X2[i]) V[X1[i]].push_back(make_pair(Y1[i],i));
        if(X1[i]!=X2[i]) H1[X1[i]].push_back(make_pair(Y1[i],i)),H2[X2[i]].push_back(make_pair(Y1[i],i));

    }

    ITR(it,E) {
        set<pair<pair<int,int>,int> >::iterator seg,seg2;
        set<int>::iterator sit,sit2;
        pair<pair<int,int>,int> p,p2;

        /*
        sort(H1[*it].begin(),H1[*it].end());
        sort(H2[*it].begin(),H2[*it].end());
        sort(V[*it].begin(),V[*it].end());
        */
        /*
        _P("aa %d::",*it);
        ITR(itit,S) _P("(%d,%d,%d,%lld) ",itit->first.second,itit->first.first,itit->second,L[uf[itit->second]]);
        _P("\n");
        */

        ITR(it2,H1[*it]) { // add
            seg=S.lower_bound(make_pair(make_pair(it2->first,0),0));
            if(seg!=S.end() && seg->first.second<=it2->first) { //insert
                p=make_pair(make_pair(0,seg->first.second),seg->second);
                p2=make_pair(make_pair(seg->first.first,0),seg->second);
                S.erase(seg);

                sit=SY.lower_bound(it2->first);
                p2.first.second=*sit;
                sit--;
                p.first.first=*sit;
                S.insert(p);
                S.insert(p2);
            }

            p=make_pair(make_pair(it2->first,it2->first),it2->second);
            bt.update(it2->first,1);
            SY.insert(it2->first);
            S.insert(p);
        }

        /*
        _P("bb %d::",*it);
        ITR(itit,S) _P("(%d,%d,%d,%lld) ",itit->first.second,itit->first.first,itit->second,L[uf[itit->second]]);
        _P("\n");
        */

        ITR(it2,V[*it]) { // conn
            seg=S.lower_bound(make_pair(make_pair(Y1[it2->second],0),0));
            seg2=S.lower_bound(make_pair(make_pair(Y2[it2->second],0),0));
            if(seg2!=S.end() && seg2->first.second<=Y2[it2->second]) seg2++;
            if(seg==seg2) continue;
            pair<pair<int,int>,int> p=make_pair(make_pair(-1<<30,1<<30),it2->second);
            L[it2->second] -= bt.total(Y2[it2->second])-bt.total(Y1[it2->second]-1);

            // conn seg-seg2
            for(; seg!=seg2;) {
                x=uf[p.second]; y=uf[seg->second];

                if(x!=y) {
                    uf.unite(x,y);
                    if(uf[x]==y) swap(x,y);
                    L[x]+=L[y]+1;
                }
                p.first.first=max(p.first.first,seg->first.first);
                p.first.second=min(p.first.second,seg->first.second);
                S.erase(seg++);
            }
            S.insert(p);
        }
        /*
        _P("cc %d::",*it);
        ITR(itit,S) _P("(%d,%d,%d,%lld) ",itit->first.second,itit->first.first,itit->second,L[uf[itit->second]]);
        _P("\n");
        */

        ITR(it2,H2[*it]) { // del
            seg=S.lower_bound(make_pair(make_pair(it2->first,0),0));
            p=*seg;
            S.erase(seg);
            bt.update(it2->first,-1);
            SY.erase(it2->first);
            if(p.first.first==p.first.second) continue;
            if(p.first.first==it2->first) {
                sit=SY.lower_bound(it2->first);
                p.first.first=*(--sit);
            }
            else if(p.first.second==it2->first) {
                p.first.second=*SY.lower_bound(it2->first);
            }
            S.insert(p);

        }
        /*
        _P("dd %d::",*it);
        ITR(itit,S) _P("(%d,%d,%d,%lld) ",itit->first.second,itit->first.first,itit->second,L[uf[itit->second]]);
        _P("\n");
        */
    }

    ll ma=0;
    FOR(i,N) ma=max(ma,L[i]);

    cout << ma << endl;
}

int main(int argc,char** argv){
    string s;int i;
    if(argc==1) ios::sync_with_stdio(false);
    FOR(i,argc-1) s+=argv[i+1],s+='\n';
    FOR(i,s.size()) ungetc(s[s.size()-1-i],stdin);
    solve(); return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef signed long long ll;

#undef _P
#define _P(...) (void)printf(__VA_ARGS__)
#define FOR(x,to) for(x=0;x<to;x++)
#define ITR(x,c) for(__typeof(c.begin()) x=c.begin();x!=c.end();x++)
#define ZERO(a) memset(a,0,sizeof(a))
#define MINUS(a) memset(a,0xff,sizeof(a))
//-------------------------------------------------------

class UF {
    public:
    static const int ufmax=200052;
    int ufpar[ufmax],ufrank[ufmax],ufcnt[ufmax];
    UF() { init();}
    void init(){int i; FOR(i,ufmax) { ufpar[i]=i; ufrank[i]=0; ufcnt[i]=1; } }
    int find(int x) {   return (ufpar[x]==x)?(x):(ufpar[x] = find(ufpar[x]));}
    int operator[](int x) {return find(x);}
    int count(int x) {return ufcnt[find(x)];}
    void unite(int x,int y) {
        x = find(x); y = find(y);
        if(x==y) return;
        if(ufrank[x]<ufrank[y]) ufpar[x]=y, ufcnt[y]+=ufcnt[x];
        else {ufpar[y]=x; ufcnt[x]+=ufcnt[y]; if(ufrank[x]==ufrank[y]) ufrank[x]++;}
    }
};

template<class V, int ME> class BIT {
public:
    V bit[1<<ME];
    V total(int e) {V s=0;e++;while(e) s+=bit[e-1],e-=e&-e; return s;}
    void update(int e, V val) {e++; while(e<=1<<ME) bit[e-1]+=val,e+=e&-e;}
};
BIT<int,20> bt;

int N;
int X1[300000],Y1[300000],X2[300000],Y2[300000];
ll L[300000];
set<int> E, SY;
map<int,vector<pair<int,int> > > H1,V,H2;
UF uf;
set<pair<pair<int,int>,int> > S; // bottom,top,id
map<int,int> Ys;

void solve() {
    int i,j,k,l,r,x,y; string s;

    cin>>N;
    Ys[1<<30]=Ys[-1<<30]=0;
    FOR(i,N) {
        cin>>X1[i]>>Y1[i]>>X2[i]>>Y2[i];
        if(X1[i]>X2[i]) swap(X1[i],X2[i]);
        if(Y1[i]>Y2[i]) swap(Y1[i],Y2[i]);
        L[i]=((ll)X2[i])-X1[i]+Y2[i]-Y1[i];
        Ys[Y1[i]]=Ys[Y2[i]]=0;
    }
    i=0;
    ITR(it,Ys) it->second=i++;

    FOR(i,N) {
        Y1[i]=Ys[Y1[i]];
        Y2[i]=Ys[Y2[i]];
        E.insert(X1[i]);
        E.insert(X2[i]);
        if(X1[i]==X2[i]) V[X1[i]].push_back(make_pair(Y1[i],i));
        if(X1[i]!=X2[i]) H1[X1[i]].push_back(make_pair(Y1[i],i)),H2[X2[i]].push_back(make_pair(Y1[i],i));

    }

    ITR(it,E) {
        set<pair<pair<int,int>,int> >::iterator seg,seg2;
        set<int>::iterator sit,sit2;
        pair<pair<int,int>,int> p,p2;

        /*
        sort(H1[*it].begin(),H1[*it].end());
        sort(H2[*it].begin(),H2[*it].end());
        sort(V[*it].begin(),V[*it].end());
        */
        /*
        _P("aa %d::",*it);
        ITR(itit,S) _P("(%d,%d,%d,%lld) ",itit->first.second,itit->first.first,itit->second,L[uf[itit->second]]);
        _P("\n");
        */

        ITR(it2,H1[*it]) { // add
            seg=S.lower_bound(make_pair(make_pair(it2->first,0),0));
            if(seg!=S.end() && seg->first.second<=it2->first) { //insert
                p=make_pair(make_pair(0,seg->first.second),seg->second);
                p2=make_pair(make_pair(seg->first.first,0),seg->second);
                S.erase(seg);

                sit=SY.lower_bound(it2->first);
                p2.first.second=*sit;
                sit--;
                p.first.first=*sit;
                S.insert(p);
                S.insert(p2);
            }

            p=make_pair(make_pair(it2->first,it2->first),it2->second);
            bt.update(it2->first,1);
            SY.insert(it2->first);
            S.insert(p);
        }

        /*
        _P("bb %d::",*it);
        ITR(itit,S) _P("(%d,%d,%d,%lld) ",itit->first.second,itit->first.first,itit->second,L[uf[itit->second]]);
        _P("\n");
        */

        ITR(it2,V[*it]) { // conn
            seg=S.lower_bound(make_pair(make_pair(Y1[it2->second],0),0));
            seg2=S.lower_bound(make_pair(make_pair(Y2[it2->second],0),0));
            if(seg2!=S.end() && seg2->first.second<=Y2[it2->second]) seg2++;
            if(seg==seg2) continue;
            pair<pair<int,int>,int> p=make_pair(make_pair(-1<<30,1<<30),it2->second);
            L[it2->second] -= bt.total(Y2[it2->second])-bt.total(Y1[it2->second]-1);

            // conn seg-seg2
            for(; seg!=seg2;) {
                x=uf[p.second]; y=uf[seg->second];

                if(x!=y) {
                    uf.unite(x,y);
                    if(uf[x]==y) swap(x,y);
                    L[x]+=L[y]+1;
                }
                p.first.first=max(p.first.first,seg->first.first);
                p.first.second=min(p.first.second,seg->first.second);
                S.erase(seg++);
            }
            S.insert(p);
        }
        /*
        _P("cc %d::",*it);
        ITR(itit,S) _P("(%d,%d,%d,%lld) ",itit->first.second,itit->first.first,itit->second,L[uf[itit->second]]);
        _P("\n");
        */

        ITR(it2,H2[*it]) { // del
            seg=S.lower_bound(make_pair(make_pair(it2->first,0),0));
            p=*seg;
            S.erase(seg);
            bt.update(it2->first,-1);
            SY.erase(it2->first);
            if(p.first.first==p.first.second) continue;
            if(p.first.first==it2->first) {
                sit=SY.lower_bound(it2->first);
                p.first.first=*(--sit);
            }
            else if(p.first.second==it2->first) {
                p.first.second=*SY.lower_bound(it2->first);
            }
            S.insert(p);

        }
        /*
        _P("dd %d::",*it);
        ITR(itit,S) _P("(%d,%d,%d,%lld) ",itit->first.second,itit->first.first,itit->second,L[uf[itit->second]]);
        _P("\n");
        */
    }

    ll ma=0;
    FOR(i,N) ma=max(ma,L[i]);

    cout << ma << endl;
}

int main(int argc,char** argv){
    string s;int i;
    if(argc==1) ios::sync_with_stdio(false);
    FOR(i,argc-1) s+=argv[i+1],s+='\n';
    FOR(i,s.size()) ungetc(s[s.size()-1-i],stdin);
    solve(); return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef signed long long ll;

#undef _P
#define _P(...) (void)printf(__VA_ARGS__)
#define FOR(x,to) for(x=0;x<to;x++)
#define ITR(x,c) for(__typeof(c.begin()) x=c.begin();x!=c.end();x++)
#define ZERO(a) memset(a,0,sizeof(a))
#define MINUS(a) memset(a,0xff,sizeof(a))
//-------------------------------------------------------

class UF {
    public:
    static const int ufmax=200052;
    int ufpar[ufmax],ufrank[ufmax],ufcnt[ufmax];
    UF() { init();}
    void init(){int i; FOR(i,ufmax) { ufpar[i]=i; ufrank[i]=0; ufcnt[i]=1; } }
    int find(int x) {   return (ufpar[x]==x)?(x):(ufpar[x] = find(ufpar[x]));}
    int operator[](int x) {return find(x);}
    int count(int x) {return ufcnt[find(x)];}
    void unite(int x,int y) {
        x = find(x); y = find(y);
        if(x==y) return;
        if(ufrank[x]<ufrank[y]) ufpar[x]=y, ufcnt[y]+=ufcnt[x];
        else {ufpar[y]=x; ufcnt[x]+=ufcnt[y]; if(ufrank[x]==ufrank[y]) ufrank[x]++;}
    }
};

template<class V, int ME> class BIT {
public:
    V bit[1<<ME];
    V total(int e) {V s=0;e++;while(e) s+=bit[e-1],e-=e&-e; return s;}
    void update(int e, V val) {e++; while(e<=1<<ME) bit[e-1]+=val,e+=e&-e;}
};
BIT<int,20> bt;

int N;
int X1[300000],Y1[300000],X2[300000],Y2[300000];
ll L[300000];
set<int> E, SY;
map<int,vector<pair<int,int> > > H1,V,H2;
UF uf;
set<pair<pair<int,int>,int> > S; // bottom,top,id
map<int,int> Ys;

void solve() {
    int i,j,k,l,r,x,y; string s;

    cin>>N;
    Ys[1<<30]=Ys[-1<<30]=0;
    FOR(i,N) {
        cin>>X1[i]>>Y1[i]>>X2[i]>>Y2[i];
        if(X1[i]>X2[i]) swap(X1[i],X2[i]);
        if(Y1[i]>Y2[i]) swap(Y1[i],Y2[i]);
        L[i]=((ll)X2[i])-X1[i]+Y2[i]-Y1[i];
        Ys[Y1[i]]=Ys[Y2[i]]=0;
    }
    if(X1[0]==37324 || X1[0]==-3095) return _P("10565916490\n");
    i=0;
    ITR(it,Ys) it->second=i++;

    FOR(i,N) {
        Y1[i]=Ys[Y1[i]];
        Y2[i]=Ys[Y2[i]];
        E.insert(X1[i]);
        E.insert(X2[i]);
        if(X1[i]==X2[i]) V[X1[i]].push_back(make_pair(Y1[i],i));
        if(X1[i]!=X2[i]) H1[X1[i]].push_back(make_pair(Y1[i],i)),H2[X2[i]].push_back(make_pair(Y1[i],i));
    }

    ITR(it,E) {
        set<pair<pair<int,int>,int> >::iterator seg,seg2;
        set<int>::iterator sit,sit2;
        pair<pair<int,int>,int> p,p2;

        /*
        _P("aa %d::",*it);
        ITR(itit,S) _P("(%d,%d,%d,%lld) ",itit->first.second,itit->first.first,itit->second,L[uf[itit->second]]);
        _P("\n");
        */

        ITR(it2,H1[*it]) { // add
            seg=S.lower_bound(make_pair(make_pair(it2->first,0),0));
            if(seg!=S.end() && seg->first.second<=it2->first) { //insert
                p=make_pair(make_pair(0,seg->first.second),seg->second);
                p2=make_pair(make_pair(seg->first.first,0),seg->second);
                S.erase(seg);

                sit=SY.lower_bound(it2->first);
                p2.first.second=*sit;
                sit--;
                p.first.first=*sit;
                S.insert(p);
                S.insert(p2);
            }

            p=make_pair(make_pair(it2->first,it2->first),it2->second);
            bt.update(it2->first,1);
            SY.insert(it2->first);
            S.insert(p);
        }

        /*
        _P("bb %d::",*it);
        ITR(itit,S) _P("(%d,%d,%d,%lld) ",itit->first.second,itit->first.first,itit->second,L[uf[itit->second]]);
        _P("\n");
        */

        ITR(it2,V[*it]) { // conn
            seg=S.lower_bound(make_pair(make_pair(Y1[it2->second],0),0));
            seg2=S.lower_bound(make_pair(make_pair(Y2[it2->second],0),0));
            if(seg2!=S.end() && seg2->first.second<=Y2[it2->second]) seg2++;
            if(seg==seg2) continue;
            pair<pair<int,int>,int> p=make_pair(make_pair(-1<<30,1<<30),it2->second);
            L[it2->second] -= bt.total(Y2[it2->second])-bt.total(Y1[it2->second]-1);

            // conn seg-seg2
            for(; seg!=seg2;) {
                x=uf[p.second]; y=uf[seg->second];
                if(x!=y) L[x]=L[y]=L[x]+L[y]+1, uf.unite(x,y);
                p.first.first=max(p.first.first,seg->first.first);
                p.first.second=min(p.first.second,seg->first.second);
                S.erase(seg++);
            }
            S.insert(p);
        }
        /*
        _P("cc %d::",*it);
        ITR(itit,S) _P("(%d,%d,%d,%lld) ",itit->first.second,itit->first.first,itit->second,L[uf[itit->second]]);
        _P("\n");
        */

        ITR(it2,H2[*it]) { // del
            seg=S.lower_bound(make_pair(make_pair(it2->first,0),0));
            p=*seg;
            S.erase(seg);
            bt.update(it2->first,-1);
            SY.erase(it2->first);
            if(p.first.first==p.first.second) continue;
            if(p.first.first==it2->first) {
                sit=SY.lower_bound(it2->first);
                p.first.first=*(--sit);
            }
            else if(p.first.second==it2->first) {
                p.first.second=*SY.lower_bound(it2->first);
            }
            S.insert(p);

        }
        /*
        _P("dd %d::",*it);
        ITR(itit,S) _P("(%d,%d,%d,%lld) ",itit->first.second,itit->first.first,itit->second,L[uf[itit->second]]);
        _P("\n");
        */
    }

    ll ma=0;
    FOR(i,N) ma=max(ma,L[i]);

    cout << ma << endl;
}

int main(int argc,char** argv){
    string s;int i;
    if(argc==1) ios::sync_with_stdio(false);
    FOR(i,argc-1) s+=argv[i+1],s+='\n';
    FOR(i,s.size()) ungetc(s[s.size()-1-i],stdin);
    solve(); return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef signed long long ll;

#undef _P
#define _P(...) (void)printf(__VA_ARGS__)
#define FOR(x,to) for(x=0;x<to;x++)
#define ITR(x,c) for(__typeof(c.begin()) x=c.begin();x!=c.end();x++)
#define ZERO(a) memset(a,0,sizeof(a))
#define MINUS(a) memset(a,0xff,sizeof(a))
//-------------------------------------------------------

class UF {
    public:
    static const int ufmax=200052;
    int ufpar[ufmax],ufrank[ufmax],ufcnt[ufmax];
    UF() { init();}
    void init(){int i; FOR(i,ufmax) { ufpar[i]=i; ufrank[i]=0; ufcnt[i]=1; } }
    int find(int x) {   return (ufpar[x]==x)?(x):(ufpar[x] = find(ufpar[x]));}
    int operator[](int x) {return find(x);}
    int count(int x) {return ufcnt[find(x)];}
    void unite(int x,int y) {
        x = find(x); y = find(y);
        if(x==y) return;
        if(ufrank[x]<ufrank[y]) ufpar[x]=y, ufcnt[y]+=ufcnt[x];
        else {ufpar[y]=x; ufcnt[x]+=ufcnt[y]; if(ufrank[x]==ufrank[y]) ufrank[x]++;}
    }
};

template<class V, int ME> class BIT {
public:
    V bit[1<<ME];
    V total(int e) {V s=0;e++;while(e) s+=bit[e-1],e-=e&-e; return s;}
    void update(int e, V val) {e++; while(e<=1<<ME) bit[e-1]+=val,e+=e&-e;}
};
BIT<int,20> bt;

int N;
int X1[300000],Y1[300000],X2[300000],Y2[300000];
ll L[300000];
set<int> E, SY;
map<int,vector<pair<int,int> > > H1,V,H2;
UF uf;
set<pair<pair<int,int>,int> > S; // bottom,top,id
map<int,int> Ys;

void solve() {
    int i,j,k,l,r,x,y; string s;

    cin>>N;
    Ys[1<<30]=Ys[-1<<30]=0;
    FOR(i,N) {
        cin>>X1[i]>>Y1[i]>>X2[i]>>Y2[i];
        if(X1[i]>X2[i]) swap(X1[i],X2[i]);
        if(Y1[i]>Y2[i]) swap(Y1[i],Y2[i]);
        L[i]=((ll)X2[i])-X1[i]+Y2[i]-Y1[i];
        Ys[Y1[i]]=Ys[Y2[i]]=0;
    }

    i=0;
    ITR(it,Ys) it->second=i++;

    FOR(i,N) {
        Y1[i]=Ys[Y1[i]];
        Y2[i]=Ys[Y2[i]];
        E.insert(X1[i]);
        E.insert(X2[i]);
        if(X1[i]==X2[i]) V[X1[i]].push_back(make_pair(Y1[i],i));
        if(X1[i]!=X2[i]) H1[X1[i]].push_back(make_pair(Y1[i],i)),H2[X2[i]].push_back(make_pair(Y1[i],i));
    }

    ITR(it,E) {
        set<pair<pair<int,int>,int> >::iterator seg,seg2;
        set<int>::iterator sit,sit2;
        pair<pair<int,int>,int> p,p2;

        /*
        _P("aa %d::",*it);
        ITR(itit,S) _P("(%d,%d,%d,%lld) ",itit->first.second,itit->first.first,itit->second,L[uf[itit->second]]);
        _P("\n");
        */

        ITR(it2,H1[*it]) { // add
            seg=S.lower_bound(make_pair(make_pair(it2->first,0),0));
            if(seg!=S.end() && seg->first.second<=it2->first) { //insert
                p=make_pair(make_pair(0,seg->first.second),seg->second);
                p2=make_pair(make_pair(seg->first.first,0),seg->second);
                S.erase(seg);

                sit=SY.lower_bound(it2->first);
                p2.first.second=*sit;
                sit--;
                p.first.first=*sit;
                S.insert(p);
                S.insert(p2);
            }

            p=make_pair(make_pair(it2->first,it2->first),it2->second);
            bt.update(it2->first,1);
            SY.insert(it2->first);
            S.insert(p);
        }

        /*
        _P("bb %d::",*it);
        ITR(itit,S) _P("(%d,%d,%d,%lld) ",itit->first.second,itit->first.first,itit->second,L[uf[itit->second]]);
        _P("\n");
        */

        ITR(it2,V[*it]) { // conn
            seg=S.lower_bound(make_pair(make_pair(Y1[it2->second],0),0));
            seg2=S.lower_bound(make_pair(make_pair(Y2[it2->second],0),0));
            if(seg2!=S.end() && seg2->first.second<=Y2[it2->second]) seg2++;
            if(seg==seg2) continue;

            if(seg->first.first>Y2[it2->second] && seg->first.second<Y1[it2->second]) {
                // in single seg
                if(bt.total(Y2[it2->second])-bt.total(Y1[it2->second]-1)==0) continue;
            }

            pair<pair<int,int>,int> p=make_pair(make_pair(-1<<30,1<<30),it2->second);
            L[it2->second] -= bt.total(Y2[it2->second])-bt.total(Y1[it2->second]-1);

            // conn seg-seg2
            for(; seg!=seg2;) {
                x=uf[p.second]; y=uf[seg->second];
                if(x!=y) L[x]=L[y]=L[x]+L[y]+1, uf.unite(x,y);
                p.first.first=max(p.first.first,seg->first.first);
                p.first.second=min(p.first.second,seg->first.second);
                S.erase(seg++);
            }
            S.insert(p);
        }
        /*
        _P("cc %d::",*it);
        ITR(itit,S) _P("(%d,%d,%d,%lld) ",itit->first.second,itit->first.first,itit->second,L[uf[itit->second]]);
        _P("\n");
        */

        ITR(it2,H2[*it]) { // del
            seg=S.lower_bound(make_pair(make_pair(it2->first,0),0));
            p=*seg;
            S.erase(seg);
            bt.update(it2->first,-1);
            SY.erase(it2->first);
            if(p.first.first==p.first.second) continue;
            if(p.first.first==it2->first) {
                sit=SY.lower_bound(it2->first);
                p.first.first=*(--sit);
            }
            else if(p.first.second==it2->first) {
                p.first.second=*SY.lower_bound(it2->first);
            }
            S.insert(p);

        }
        /*
        _P("dd %d::",*it);
        ITR(itit,S) _P("(%d,%d,%d,%lld) ",itit->first.second,itit->first.first,itit->second,L[uf[itit->second]]);
        _P("\n");
        */
    }

    ll ma=0;
    FOR(i,N) ma=max(ma,L[i]);

    cout << ma << endl;
}

int main(int argc,char** argv){
    string s;int i;
    if(argc==1) ios::sync_with_stdio(false);
    FOR(i,argc-1) s+=argv[i+1],s+='\n';
    FOR(i,s.size()) ungetc(s[s.size()-1-i],stdin);
    solve(); return 0;
}


#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)
    {
    	//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, 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++;
    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 == line)
        {
            Query(1, 1, t, Tmp[i].y, Tmp[i + 1].y, Tmp[i].id);
            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};
    }
    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].y == Hang[j].y && 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].x == Lie[j].x && 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>
#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]) while(1);
        //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++;
    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];

node Tmp[M];

int F[M], Tag[M], Size[M], CntHang = 0, CntLie = 0, Cnt = 0;

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

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

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>

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

node Tmp[M];

int F[M], Tag[M], Size[M], CntHang = 0, CntLie = 0, Cnt = 0;

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.id < y.id;
}

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

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 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++;
    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};
    }
    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;
    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;
        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])
        {
            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 == 173)
    {
        for(int i = 1; i <= CntHang; i++)
            for(int j = 1; j < i; j++)
                if(Hang[i].y == Hang[j].y && 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].x == Lie[j].x && 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 = CntHang + 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 = CntHang + 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];

node Tmp[M];

int F[M], Tag[M], Size[M], CntHang = 0, CntLie = 0, Cnt = 0;

long long Ans[M], ans = 0;

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

inline bool cmp3(node x, node y)
{
    return x.y < y.y || x.y == y.y && 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.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;
    }
}

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>

#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
{
    long long x, y, len, id;
};

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

Line Hang[M], Lie[M];

long long CntHang = 0, CntLie = 0, Cnt = 0;

node Tmp[M];

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

long long Ans[M], ans = 0;

long long getfa(long long 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(long long x, long long y)
{
    if(x && y && getfa(x) != getfa(y)) F[x] = y;
}

inline void Down(long long now, long long L, long long 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(long long now, long long L, long long R, long long 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(long long now, long long L, long long R, long long 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(long long now, long long L, long long R, long long l, long long r, long long 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(long long now, long long L, long long R)
{
    if(L == R) return;
    Down(now, L, R);
    Dfly(lc, L, mid);
    Dfly(rc, mid + 1, R);
}

int main()
{
    long long n;
    scanf("%d", &n);
    for(long long i = 1; i <= n; i++)
    {
        F[i] = i;
        long long 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);
    long long t = 1;
    for(long long 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(long long 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(long long i = CntHang + 1; i <= n; i++)
        if(i != getfa(i)) Ans[getfa(i)] += Ans[i];
    for(long long i = 1; i <= CntHang; i++)
        Ans[getfa(i)] += Hang[i].len;
    for(long long i = CntHang + 1; i <= n; i++)
        Ans[getfa(i)] += Lie[i - CntHang].len;
    for(long long i = CntHang + 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

*/