/*
最终的白色区域一定满足如下性质：
(1)白色区域是一个矩形。该性质可以归纳：初始是一个白色区域，然后一个白色区域的矩形被按照题目规则染黑后，剩下的显然还是一个矩形
(2)矩形的内部没有点。反证即可：任选一矩形内部的点，不论该点如何操作，都会使得矩形缩小
(3)矩形的四个边界上都一定有点（在端点上也是可以的）。因为矩形的边界是被至少一个点限制得到的，而限制某一边界的点一定在边界上
同时，只要找到一个满足以上3条性质的矩形，也一定可以被一种方案构造出来
具体而言，边界上的点限制边界，不在边界上的点选择不影响该矩形的操作，即可构造
问题转换成找到一个周长最大的满足3个条件的子矩形。那么可以去掉(3)条件，因为不满足(3)条件的矩形可以继续扩展边界，故一定不是最优解
即找到一个周长最大的内部无坏点的子矩形
*/
/*
直接做这个问题有一定难度，考虑观察答案的性质
首先构造答案的下界。当所有点都是坏点时，Ans = 2 * (max(W, H) + 1)，这显然是答案的下界
可以证明，最优方案必定和直线x = floor(W / 2)或直线y = floor(H / 2)相交
反证：假设不与这两条直线相交，那么在所有点都不是坏点时，取到上界Ans' = 2 * (ceil((W + 1) / 2) - 1 + ceil((H + 1) / 2) - 1) <= (W + 1) + (H + 1) - 4
而(W + 1) + (H + 1) - 4 = W + H - 2 < 2 * max((W, H) + 1)，所以这样的方案一定不会成为最优解
那么求跨过x = floor(W / 2)的答案和跨过y = floor(H / 2)的答案即可
*/
/*
求跨过一条竖线x = p的答案，把坏点分在直线的左右两边
以右边为例，枚举哪个点卡在了答案的右边界上，那么可以算出这时候右半部分的上下边界，即y坐标不小于它最小的和y坐标不大于它最大的（特殊考虑在顶点上的情况）
注意考虑答案边界在矩形边界上的情况 
那么对于每个点有三个信息[l, r]表示上下边界和x表示到直线的距离
答案是由左右两部分拼起来来的，即找到两个点左右的两个点i和j，最大化2 * (min(ri, rj) - max(li, lj) + xi + xj)
直接用线段树维护即可 
*/

#include <set>
#include <cstdio>
#include <algorithm>

using namespace std;
const int Max_N(300050);
const int INF(0X2F2F2F2F);

namespace io
{
	const int SIZE = (1 << 21) + 1;
	char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55]; int f, qr;
	#define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
	inline void flush (){fwrite (obuf, 1, oS - obuf, stdout);oS = obuf;}
	inline void putc (char x){*oS ++ = x;if (oS == oT) flush ();}
	template <class I>
	inline void gi (I &x) {for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) if (c == '-') f = -1;
		for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15); x *= f;}
	template <class I>
	inline void print (I x){
		if (!x) putc ('0'); if (x < 0) putc ('-'), x = -x;while(x) qu[++ qr] = x % 10 + '0',  x /= 10;while (qr) putc (qu[qr--]);}
	struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
}
using io::gi;
using io::putc;
using io::print;

struct point
{
	int x, y;
};
int W, H, N, Ans;
point V[Max_N];

inline bool comp_point(const point &a, const point &b)
{
	return a.x < b.x;
}

struct inf
{
	int l, r, x;
};
int A, B;
inf X[Max_N * 2 + Max_N], Y[Max_N * 2 + Max_N];

inline bool comp_inf(const inf &a, const inf &b)
{
	return a.l < b.l;
}

#define LCH  (segt[cur].lch)
#define RCH  (segt[cur].rch)
#define MAX1 (segt[cur].Max1)
#define MAX2 (segt[cur].Max2)

struct node
{
	int lch, rch, Max1, Max2;
};
int tot, root;
node segt[Max_N * 100];

void insert(int &cur, const int &pos, const int &v1, const int &v2, const int &LEFT = 0, const int &RIGHT = H)
{
	if (!cur)
		segt[++tot] = segt[cur], cur = tot;
	MAX1 = max(MAX1, v1), MAX2 = max(MAX2, v2);
	if (LEFT == RIGHT)
		return;
	int MID = LEFT + ((RIGHT - LEFT) >> 1);
	if (pos <= MID)
		insert(LCH, pos, v1, v2, LEFT, MID);
	else
		insert(RCH, pos, v1, v2, MID + 1, RIGHT);
}

int query(const int &cur, const int &l, const int &r, const int &c, const int &LEFT = 0, const int &RIGHT = H)
{
	if (!cur)
		return -INF;
	if (LEFT == l && RIGHT == r)
		return c == 1 ? MAX1 : MAX2;
	int MID = LEFT + ((RIGHT - LEFT) >> 1);
	if (r <= MID)
		return query(LCH, l, r, c, LEFT, MID);
	else
		if (l > MID)
			return query(RCH, l, r, c, MID + 1, RIGHT);
		else
			return max(query(LCH, l, MID, c, LEFT, MID), query(RCH, MID + 1, r, c, MID + 1, RIGHT));
}

void work()
{
	A = B = 0;
	sort(V + 1, V + 1 + N, comp_point);
	int start;
	set<int> S;
	set<int>::iterator iter;
	for (start = 1;start <= N;++start)
		if (V[start].x >= W / 2)
			break;
	S.clear();
	S.insert(0), S.insert(H);
	for (int i = start, j = start;i <= N;++i)
	{
		while (j < i && V[j].x < V[i].x)
			S.insert(V[j++].y);
		if (S.count(V[i].y))
		{
			if (V[i].y != 0)
			{
				--(iter = S.lower_bound(V[i].y));
				++A, X[A].x = V[i].x - W / 2, X[A].l = *iter, X[A].r = V[i].y;
			}
			if (V[i].y != H)
			{
				iter = S.upper_bound(V[i].y);
				++A, X[A].x = V[i].x - W / 2, X[A].l = V[i].y, X[A].r = *iter;
			}
		}
		else
		{
			X[++A].x = V[i].x - W / 2;
			iter = S.upper_bound(V[i].y);
			X[A].r = *iter, X[A].l = *(--iter);
		}
	}
	for (iter = S.begin();iter != S.end();++iter)
		if (iter != S.begin())
			X[++A].x = W - W / 2, X[A].l = *(--iter), X[A].r = *(++iter);
	for (start = N;start >= 1;--start)
		if (V[start].x <= W / 2)
			break;
	S.clear();
	S.insert(0), S.insert(H);
	for (int i = start, j = start;i >= 1;--i)
	{
		while (j > i && V[j].x > V[i].x)
			S.insert(V[j--].y);
		if (S.count(V[i].y))
		{
			if (V[i].y != 0)
			{
				--(iter = S.lower_bound(V[i].y));
				++B, Y[B].x = W / 2 - V[i].x, Y[B].l = *iter, Y[B].r = V[i].y;
			}
			if (V[i].y != H)
			{
				iter = S.upper_bound(V[i].y);
				++B, Y[B].x = W / 2 - V[i].x, Y[B].l = V[i].y, Y[B].r = *iter;
			}
		}
		else
		{
			Y[++B].x = W / 2 - V[i].x;
			iter = S.upper_bound(V[i].y);
			Y[B].r = *iter, Y[B].l = *(--iter);
		}
	}
	for (iter = S.begin();iter != S.end();++iter)
		if (iter != S.begin())
			Y[++B].x = W / 2 - 0, Y[B].l = *(--iter), Y[B].r = *(++iter);
	sort(X + 1, X + 1 + A, comp_inf), sort(Y + 1, Y + 1 + B, comp_inf);
	tot = root = 0, segt[0].lch = segt[0].rch = 0, segt[0].Max1 = segt[0].Max2 = -INF;
	for (int i = 1, j = 1;i <= A;++i)
	{
		while (j <= B && Y[j].l <= X[i].l)
			insert(root, Y[j].r, Y[j].x, Y[j].x + Y[j].r), ++j;
		Ans = max(Ans, 2 * (X[i].x - X[i].l + max(query(root, 0, X[i].r, 2), query(root, X[i].r, H, 1) + X[i].r)));
	}
	tot = root = 0, segt[0].lch = segt[0].rch = 0, segt[0].Max1 = segt[0].Max2 = -INF;
	for (int i = 1, j = 1;i <= B;++i)
	{
		while (j <= A && X[j].l <= Y[i].l)
			insert(root, X[j].r, X[j].x, X[j].x + X[j].r), ++j;
		Ans = max(Ans, 2 * (Y[i].x - Y[i].l + max(query(root, 0, Y[i].r, 2), query(root, Y[i].r, H, 1) + Y[i].r)));
	}
}

int main()
{
	gi(W), gi(H), gi(N);
	for (int i = 1;i <= N;++i)
		gi(V[i].x), gi(V[i].y);
	++N, V[N].x = 0, V[N].y = 0;
	++N, V[N].x = 0, V[N].y = H;
	++N, V[N].x = W, V[N].y = 0;
	++N, V[N].x = W, V[N].y = H;
	work();
	swap(W, H);
	for (int i = 1;i <= N;++i)
		swap(V[i].x, V[i].y);
	work();
	print(Ans);
	return 0;
}

Measured memory_bytes: 61568