#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <string>
#include <cstring>
#define pb push_back
#define mp make_pair
#define ll long long
using namespace std;
const int MAXQ = 5e4 + 5;
const int INF = 1e9;
const int MAXX = 1e6;

struct node{

    int ans;
    int fb, fe;
    int min_val;
    int sz;

    node() {}
    node(int _min_val, int _fb, int _fe, int _ans, int _sz)
    {
        min_val = _min_val;
        fb = _fb;
        fe = _fe;
        ans = _ans;
        sz = _sz;
    }

};

struct seg_tree{

    node t[4 * MAXX + 5];
    int lazy[4 * MAXX + 5];

    node combine(node l, node r)
    {
        node res;
        if(l.min_val < r.min_val)
        {
            res = l;
            res.fe = 0;
            return res;
        }
        if(l.min_val > r.min_val)
        {
            res = r;
            res.fb = 0;
            return res;
        }

        res.min_val = l.min_val;
        res.ans = max(l.ans, r.ans);
        res.fb = l.fb;
        res.fe = r.fe;
        res.sz = l.sz + r.sz;

        if(l.fb == l.sz)
        {
            res.ans = max(res.ans, l.sz + r.fb);
            res.fb = l.sz + r.fb;
        }
        if(r.fe == r.sz)
        {
            res.ans = max(res.ans, r.sz + l.fe);
            res.fe = r.sz + l.fe;
        }

        return res;
    }

    void build_tree(int pos, int low, int high)
    {
        if(low == high)
        {
            t[pos] = node(0, 1, 1, 1, 1);
            return;
        }

        int mid = (low + high) / 2;
        build_tree(pos * 2, low, mid);
        build_tree(pos * 2 + 1, mid + 1, high);

        t[pos] = combine(t[pos * 2], t[pos * 2 + 1]);
    }

    void refresh(int pos, int low, int high)
    {
        if(!lazy[pos])
            return;

        t[pos].min_val += lazy[pos];
        if(low < high)
        {
            lazy[pos * 2] += lazy[pos];
            lazy[pos * 2 + 1] += lazy[pos];
        }
        lazy[pos] = 0;
    }

    void update(int pos, int low, int high, int l, int r, int x)
    {
        refresh(pos, low, high);
        if(l > high || r < low)
            return;
        if(l <= low && r >= high)
        {
            lazy[pos] += x;
            refresh(pos, low, high);
            return;
        }

        int mid = (low + high) / 2;
        update(pos * 2, low, mid, l, r, x);
        update(pos * 2 + 1, mid + 1, high, l, r, x);

        t[pos] = combine(t[pos * 2], t[pos * 2 + 1]);
    }

    node query(int pos, int low, int high, int l, int r)
    {
        refresh(pos, low, high);
        if(l > high || r < low)
            return node(INF, 0, 0, 0, 0);
        if(l <= low && r >= high)
            return t[pos];

        int mid = (low + high) / 2;

        return combine(query(pos * 2, low, mid, l, r), query(pos * 2 + 1, mid + 1, high, l, r));
    }

    void clear()
    {
        memset(lazy, 0, sizeof(lazy));
        build_tree(1, 1, MAXX);
    }

}seg;


int n, m, Q;
struct Event{

    int id;
    int add;
    int l, r, y;

    Event() {}
    Event(int _add, int _l, int _r, int _y)
    {
        add = _add;
        l = _l;
        r = _r;
        y = _y;
    }

    bool operator < (const Event &other)
    {
        if(y != other.y)
            return y < other.y;
        if(add != other.add)
            return add > other.add;
        return l < other.l;
    }
}event[2 * MAXQ];

int events;
int x1[MAXQ], y1[MAXQ], x2[MAXQ], y2[MAXQ];

void make_events(int mid)
{
    for(int i = 1; i <= Q; i++)
    {
        event[i] = Event(1, y1[i], y2[i], x1[i]);
        event[i + Q] = Event(-1, y1[i], y2[i], x2[i] + mid);
    }
    event[2 * Q + 1] = Event(0, 1, m, mid);
    event[2 * Q + 2] = Event(0, 1, m, n);

    sort(event + 1, event + events + 1);
}

int ans;
bool check(int mid)
{
    make_events(mid);
    seg.clear();

    int l, r, x;
    for(int i = 1; i <= events; i++)
    {
        if(event[i].y > n)
            break;

        l = event[i].l;
        r = event[i].r;
        x = event[i].add;

        seg.update(1, 1, MAXX, l, r, x);

        node t = seg.query(1, 1, MAXX, 1, m);
        if(t.ans >= mid)
            return true;
    }

    return false;
}


int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);

    cin >> n >> m >> Q;

    events = 2 * Q + 2;
    for(int i = 1; i <= Q; i++)
        cin >> x1[i] >> y1[i] >> x2[i] >> y2[i];


    int low = 1, high = MAXX;
    while(low <= high)
    {
        int mid = (low + high) / 2;
        if(check(mid))
        {
            ans = mid;
            low = mid + 1;
        }
        else
            high = mid - 1;
    }

    cout << ans << endl;

    return 0;
}

/*

6 5
4
1 2 1 5
1 4 5 4
5 2 5 2
1 2 1 5

*/
