#include <bits/stdc++.h>
int IntMaxVal = (int)1e20;
int IntMinVal = (int)-1e20;
template <typename T>
inline void maximize(T& a, T b) {
  a = std::max(a, b);
}
using namespace std;
class {
  vector<int> parent;
  vector<int> size;
  vector<long long> perimeter;

 public:
  void init(int n) {
    parent.resize(n);
    for (int i = 0; i < n; i++) parent[i] = i;
    size.assign(n, 1);
    perimeter.resize(n);
  }
  int get(int v) {
    if (v == parent[v]) return v;
    return parent[v] = get(parent[v]);
  }
  int join(int a, int b) {
    a = get(a);
    b = get(b);
    if (a == b) return a;
    if (size[a] < size[b]) swap(a, b);
    size[a] += size[b];
    perimeter[a] += perimeter[b];
    parent[b] = a;
    return a;
  }
  void add_perimeter(int v, long long addition) {
    v = get(v);
    perimeter[v] += addition;
  }
  long long get_perimeter(int v) {
    v = get(v);
    return perimeter[v];
  }
} dsu;
struct list_element {
  int top;
  int bottom;
  int id;
  list_element(int y, int id) {
    top = bottom = y;
    this->id = id;
  }
};
struct {
  int gp2(int n) {
    int x = 2;
    while (x < n) x *= 2;
    return x;
  }
  int n;
  vector<int> points_count;
  vector<int> leftmost;
  vector<int> rightmost;
  vector<int> leftmost_set_element;
  vector<int> rightmost_set_element;
  void init(vector<int> points) {
    sort(points.begin(), points.end());
    points.resize(unique(points.begin(), points.end()) - points.begin());
    n = gp2(points.size());
    points_count.resize(2 * n);
    leftmost.assign(2 * n, IntMaxVal);
    rightmost.assign(2 * n, IntMaxVal);
    for (int i = 0; i < points.size(); ++i)
      leftmost[n + i] = rightmost[n + i] = points[i];
    for (int i = n - 1; i >= 1; --i) leftmost[i] = leftmost[2 * i];
    for (int i = n - 1; i >= 1; --i) rightmost[i] = rightmost[2 * i + 1];
    leftmost_set_element.assign(2 * n, IntMaxVal);
    rightmost_set_element.assign(2 * n, IntMinVal);
  }
  void update(int key, int val) {
    int ptr = 1;
    while (ptr < n) {
      ptr *= 2;
      if (leftmost[ptr + 1] <= key) ptr++;
    }
    points_count[ptr] = val;
    leftmost_set_element[ptr] = val ? leftmost[ptr] : IntMaxVal;
    rightmost_set_element[ptr] = val ? leftmost[ptr] : IntMinVal;
    ptr /= 2;
    while (ptr) {
      points_count[ptr] = points_count[2 * ptr] + points_count[2 * ptr + 1];
      leftmost_set_element[ptr] =
          min(leftmost_set_element[2 * ptr], leftmost_set_element[2 * ptr + 1]);
      rightmost_set_element[ptr] = max(rightmost_set_element[2 * ptr],
                                       rightmost_set_element[2 * ptr + 1]);
      ptr /= 2;
    }
  }
  void add(int y) { update(y, 1); }
  void remove(int y) { update(y, 0); }
  int count(int y1, int y2, int i = 1) {
    if (leftmost[i] >= y1 && rightmost[i] <= y2) return points_count[i];
    if (leftmost[i] > y2 || rightmost[i] < y1) return 0;
    return count(y1, y2, 2 * i) + count(y1, y2, 2 * i + 1);
  }
  int get_first_after(int y, int ptr = 1) {
    if (leftmost[ptr] > y) return leftmost_set_element[ptr];
    if (rightmost[ptr] <= y) return IntMaxVal;
    return min(get_first_after(y, 2 * ptr), get_first_after(y, 2 * ptr + 1));
  }
  int get_last_before(int y, int ptr = 1) {
    if (rightmost[ptr] < y) return rightmost_set_element[ptr];
    if (leftmost[ptr] >= y) return IntMinVal;
    return max(get_last_before(y, 2 * ptr), get_last_before(y, 2 * ptr + 1));
  }
} current_horizontal_lines;
struct {
  map<int, list_element*> elements;
  list_element* find_first(int y) {
    map<int, list_element*>::iterator it = elements.lower_bound(y);
    if (it == elements.end()) return NULL;
    return it->second;
  }
  void insert(list_element* newElement) {
    elements[newElement->top] = newElement;
  }
  void split(list_element* element, int y) {
    assert(element->bottom < y);
    assert(element->top > y);
    int bottom = element->bottom;
    element->bottom = current_horizontal_lines.get_first_after(y);
    list_element* bottom_part = new list_element(bottom, element->id);
    bottom_part->top = current_horizontal_lines.get_last_before(y);
    insert(bottom_part);
  }
  void remove(list_element* element) { elements.erase(element->top); }
  void debug_print() {
    cout << "List contents : " << endl;
    map<int, list_element*>::iterator ptr = elements.begin();
    while (ptr != elements.end()) {
      cout << "( " << ptr->second->bottom << " , " << ptr->second->top << " ) "
           << endl;
      ptr++;
    }
  }
} linked_list;
struct vertical_line {
  int x, y1, y2, id;
};
struct horizontal_line_point {
  int x, y, id;
};
void start_horizontal_line(horizontal_line_point& point) {
  list_element* first_after = linked_list.find_first(point.y);
  list_element* newElement = new list_element(point.y, point.id);
  current_horizontal_lines.add(point.y);
  if (first_after != NULL && first_after->bottom < point.y) {
    linked_list.split(first_after, point.y);
  }
  linked_list.insert(newElement);
}
void sweep_vertical(vertical_line& line) {
  list_element* firstAfter = linked_list.find_first(line.y1);
  if (firstAfter == NULL || firstAfter->bottom > line.y2 ||
      current_horizontal_lines.count(line.y1, line.y2) == 0)
    return;
  int different_line_sets = 0;
  while (true) {
    list_element* next_element = linked_list.find_first(firstAfter->top + 1);
    if (next_element == NULL || next_element->bottom > line.y2) break;
    if (dsu.get(firstAfter->id) != dsu.get(next_element->id)) {
      next_element->id = dsu.join(firstAfter->id, next_element->id);
      different_line_sets++;
    }
    next_element->bottom = firstAfter->bottom;
    linked_list.remove(firstAfter);
    firstAfter = next_element;
  }
  dsu.join(firstAfter->id, line.id);
  int perimeter_add = 0;
  perimeter_add -= current_horizontal_lines.count(line.y1, line.y2) - 1;
  perimeter_add += different_line_sets;
  dsu.add_perimeter(firstAfter->id, perimeter_add);
}
void end_horizontal_line(horizontal_line_point& point) {
  current_horizontal_lines.remove(point.y);
  list_element* element = linked_list.find_first(point.y);
  assert(element != NULL);
  assert(element->bottom <= point.y);
  if (element->bottom == element->top) {
    linked_list.remove(element);
  } else if (element->bottom == point.y) {
    element->bottom = current_horizontal_lines.get_first_after(point.y);
  } else if (element->top == point.y) {
    linked_list.remove(element);
    element->top = current_horizontal_lines.get_last_before(point.y);
    linked_list.insert(element);
  }
}
template <typename T>
bool leftToRight(const T& x, const T& y) {
  return x.x < y.x;
}
int main() {
  ios_base::sync_with_stdio(false);
  deque<vertical_line> vertical_lines;
  deque<horizontal_line_point> horizontal_line_starts;
  deque<horizontal_line_point> horizontal_line_ends;
  int n;
  cin >> n;
  dsu.init(n);
  vector<int> horizontal_line_ys;
  for (int i = 0; i < n; ++i) {
    int x1, y1, x2, y2;
    cin >> x1 >> y1 >> x2 >> y2;
    if (x1 == x2) {
      vertical_line line = {x1, min(y1, y2), max(y1, y2), i};
      vertical_lines.push_back(line);
    } else {
      horizontal_line_point start = {min(x1, x2), y1, i};
      horizontal_line_point end = {max(x1, x2), y1, i};
      horizontal_line_starts.push_back(start);
      horizontal_line_ends.push_back(end);
      horizontal_line_ys.push_back(y1);
    }
    dsu.add_perimeter(i, x2 - x1 + y2 - y1);
  }
  sort(vertical_lines.begin(), vertical_lines.end(),
       leftToRight<vertical_line>);
  sort(horizontal_line_starts.begin(), horizontal_line_starts.end(),
       leftToRight<horizontal_line_point>);
  sort(horizontal_line_ends.begin(), horizontal_line_ends.end(),
       leftToRight<horizontal_line_point>);
  vertical_line vLine_stub = {IntMaxVal, 0, 0};
  horizontal_line_point hPoint_stub = {IntMaxVal, 0, 0};
  vertical_lines.push_back(vLine_stub);
  horizontal_line_starts.push_back(hPoint_stub);
  horizontal_line_ends.push_back(hPoint_stub);
  current_horizontal_lines.init(horizontal_line_ys);
  while (vertical_lines.size() > 1 || horizontal_line_starts.size() > 1 ||
         horizontal_line_ends.size() > 1) {
    int minX = min(
        vertical_lines.front().x,
        min(horizontal_line_starts.front().x, horizontal_line_ends.front().x));
    if (horizontal_line_starts.front().x == minX) {
      start_horizontal_line(horizontal_line_starts.front());
      horizontal_line_starts.pop_front();
    } else if (vertical_lines.front().x == minX) {
      sweep_vertical(vertical_lines.front());
      vertical_lines.pop_front();
    } else {
      end_horizontal_line(horizontal_line_ends.front());
      horizontal_line_ends.pop_front();
    }
  }
  long long result = 0;
  for (int i = 0; i < n; ++i) maximize(result, dsu.get_perimeter(i));
  cout << result;
}
